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;
}