Java 为什么不能从beanClass获取注释?

Java 为什么不能从beanClass获取注释?,java,spring,annotations,aop,Java,Spring,Annotations,Aop,我有一个带有Transactional注释和Component注释的类EnterLog是我的自定义注释,用于按aop打印日志 @Transactional @Component @EntranceLog public class TransferServiceImpl implements TransferService { xxxx } 这是我的注释。在Spring中@Transactional已经是一个AOP处理过的注释,因此添加自己的注释将需要一些额外的工作。让我解释一下Sp

我有一个带有
Transactional
注释和
Component
注释的类
EnterLog
是我的自定义注释,用于按aop打印日志

@Transactional
@Component
@EntranceLog
public class TransferServiceImpl implements TransferService {

    xxxx

}

这是我的注释。

在Spring中
@Transactional
已经是一个AOP处理过的注释,因此添加自己的注释将需要一些额外的工作。让我解释一下Spring AOP和
@Transactional
是如何工作的

Spring有两种实现AOP的方法,如果类实现了接口,它可以使用标准JDK代理;如果类没有实现接口,它将通过使用CGLib在运行时发出字节码来创建一个新的子类。除非您非常小心,否则您几乎总是会得到一个带有SpringAOP的CGLib代理

当Spring遇到一个
@Transactional
(类或方法级别)时,它使用CGLib创建一个新的子类,您可以将这个类看作一个装饰器,它将所有调用转发给您的实现类。在执行之前和之后(围绕通知),它检查
@Transactional
注释属性,并检查线程本地存储以查看事务是否已经存在,如果没有事务,它将创建一个事务,并记住它,以便以后可以提交它。如果在
Transactional
方法中设置一个breakpoint,并查看调用堆栈,您将看到对实现的调用来自decorator类,并且没有用于它的源代码

在您的例子中,添加到应用程序上下文的bean不是您的
TransferServiceImpl
bean,而是Spring在类上找到
@Transactional
注释时创建的CGLib代理,它将被命名为类似于
TransferServiceImpl$$FastClassBySpringCGLIB$$
——这个类没有
@enterLog
注释,这就是您自己的方面无法工作的原因


我自己从来没有遇到过这个问题,因为我总是试图避免AOP,或者总是在已经由Spring代理CGLib的类上。除非您想深入研究Spring源代码,或者在Spring开发团队中找到人来帮助您,否则我建议您创建另一个间接层,这样您就不需要在同一个类中处理两个方面。

对于那些不愿意或无法更改代码结构以避免此问题的人,以下可能会有所帮助:

正如Klaus提到的,Spring在遇到标记为
@Transactional
的类时会创建一个decorator类。但是,因为这个新类只是一个装饰器,所以您应该能够调用
beanClass
上的
getSuperclass()
来提供Spring正在装饰的实际类,如下所示:

beanClass.getSuperclass().getAnnotations()

如果您正在使用自己的注释,请通过使用以下内容注释注释类,确保注释在整个运行时都保持不变:


@Retention(RetentionPolicy.RUNTIME)

注释的定义是什么?它是否在编译过程中持续存在?@vegaasen是的,它可以在编译过程中持续存在。注释的定义很简单。我的目的是用
enterlog
annotation代理bean,但当应用程序启动时,我无法从bean中获得任何批注。我建议您添加批注的代码,可能是其定义中的某些内容阻止了它persisting@niceman我添加注释的代码。@vegaasen我添加注释的代码。事实上,我应该为我的事务处理程序添加另一层,而不应该在我公开的服务中添加
Transactional
。这对我来说是个很好的答案,谢谢。
public class LogProxyCreator extends AbstractAutoProxyCreator implements ApplicationContextAware {

    private static final LogInterceptor LOG = new LogInterceptor();

    private static Logger log = LoggerFactory.getLogger(LogProxyCreator.class);

    @Override
    protected Object[] getAdvicesAndAdvisorsForBean(Class<?> beanClass, String s, TargetSource targetSource) throws BeansException {
        Annotation anno = null;

        for (Annotation annotationTemp : beanClass.getAnnotations()) {
            Log temp = annotationTemp.annotationType().getAnnotation(EntranceLog.class);
            if (temp != null) {
                anno = temp;
                break;
            }
        }

        if (anno == null) {
            return null;
        }
        Object[] additional =  new Object[]{LOG};

        log.error(beanClass.getName() + " has register the fc log.");

        return additional;
    }

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        LOG.setContext(applicationContext);
    }
}
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE})
@Log(logName = "entrance")
public @interface EntranceLog {
    @AliasFor(
        annotation = Log.class,
        attribute = "subLogName"
    )
    String logName() default "";

    @AliasFor(
        annotation = Log.class,
        attribute = "openInfoLog"
    )
    boolean openInfoLog() default false;
}