现象
:当类的方法使用Spring事务注解@Transactional后,再使用isAnnotationPresent(Class)判断类方法是否包含注解时,会一直返回false,无法正确获取类方法注解。
测试代码
方法注解@JobHandler
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
@Inherited
public @interface JobHandler {
String value();
}
类注解@JobWorker
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Inherited
@Component
public @interface JobWorker {
}
第一种情况
:不使用Spring的事务注解@Transactional,可以正确的拿到方法的注解,测试类如下
@JobWorker
public class HelloAnnotation {
@JobHandler("sayHello")
public void sayHello() {
System.out.println("hello annotation");
}
// @Transactional
public void insert() {
System.out.println("插入成功");
}
}
测试方法
@Test
public void testIsAnnotationPresent() {
Map<String, Object> serviceBeanMap = applicationContext.getBeansWithAnnotation(JobWorker.class);
for (Object serviceBean : serviceBeanMap.values()) {
System.out.println(">>>>>>>> 标记了@JobWorker注解的类" + serviceBean.getClass());
Method[] methods = serviceBean.getClass().getDeclaredMethods();
for (Method method : methods) {
if (method.isAnnotationPresent(JobHandler.class)) {
System.out.println(">>>>>>>> " + method.getName() + "包含注解@JobHandler");
} else {
System.out.println(">>>>>>>> " + method.getName() + "不包含注解@JobHandler");
}
}
}
}
测试结果:可以看到正确判断方法是否包含的注解,特别注意的是获取到标记了@JobWorker注解的类是class com.demo.mybatis.anno.HelloAnnotation
>>>>>>>> 标记了@JobWorker注解的类class com.demo.mybatis.anno.HelloAnnotation
>>>>>>>> insert不包含注解@JobHandler
>>>>>>>> sayHello包含注解@JobHandler
第二种情况
:使用Spring的事务注解@Transactional,isAnnotationPresent(Class)就无法正确的拿到方法的注解了,测试类如下
@JobWorker
public class HelloAnnotation {
@JobHandler("sayHello")
public void sayHello() {
System.out.println("hello annotation");
}
@Transactional
public void insert() {
System.out.println("插入成功");
}
}
测试结果,可以看到HelloAnnotation类被Spring生成的代理类包含了。造成了无法正确获得方法注解。原因是这个类在事务管理时,被当成了类代理。根据class反射拿到的是代理类,所以拿不到对应的注解。
>>>>>>>> 标记了@JobWorker注解的类class com.demo.mybatis.anno.HelloAnnotation$$EnhancerBySpringCGLIB$$718f198e
>>>>>>>> insert不包含注解@JobHandler
>>>>>>>> sayHello不包含注解@JobHandler
>>>>>>>> CGLIB$sayHello$1不包含注解@JobHandler
>>>>>>>> CGLIB$insert$0不包含注解@JobHandler
总结
:使用了Spring的事务注解@Transactional后,原目标类被当成了类代理。根据class反射拿到的是代理类,代理类的方法不包含方法注解,所以拿不到对应的注解。
使用了Spring的事务注解@Transactional后,获取原类注解的方法
直接获取代理类的父亲即可,因为代理类是继承原类的,获取方法如下
@Test
public void testIsAnnotationPresent() {
Map<String, Object> serviceBeanMap = applicationContext.getBeansWithAnnotation(JobWorker.class);
for (Object serviceBean : serviceBeanMap.values()) {
// 直接获取代理类的父类getSuperclass()
System.out.println(">>>>>>>> 代理类,标记了@JobWorker注解的类" + serviceBean.getClass().getSuperclass());
Method[] methods = serviceBean.getClass().getSuperclass().getDeclaredMethods();
for (Method method : methods) {
if (method.isAnnotationPresent(JobHandler.class)) {
System.out.println(">>>>>>>> " + method.getName() + "包含注解@JobHandler");
} else {
System.out.println(">>>>>>>> " + method.getName() + "不包含注解@JobHandler");
}
}
}
}
测试结果