最近在开发过程中遇到了注解被抹掉的情况。
背景:引入调度框架,接入方式很简单需要在job类上打上注解@Schedule
(包含@Component
)使其成为spring的bean,然后在类中方法打上@Assignment
注解,这样通过这个bean获取method,在通过method方法过滤存在@Assignment
注解的方法即可。
Class<?> clazz = bean.getClass();
Method[] methods = clazz.getMethods();
if (methods != null && methods.length > 0) {
for (final Method method : methods) {
if (method.isAnnotationPresent(Assignment.class)) { 都为false
......
}
}
}
但是在使用时确总是筛选不出方法,都不带有@Assignment
注解,明明已经打上了标签。
分析:因为项目中使用了spring aop cglib
猜测是和这个有关系,为了清晰说明这个问题新建了个demo,目录结构如下:
目录结构
WillErase.java
@Documented
@Inherited
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE, ElementType.METHOD})
public @interface WillErase {
}
EraseAspect.java
@Aspect
@Component
public class EraseAspect {
@Pointcut(value = "@annotation(com.example.demo.anno.WillErase)")
public void pointcut() {
}
@Around(value = "pointcut()")
public void before(ProceedingJoinPoint pjp) throws Throwable {
System.out.println("======begin=======");
pjp.proceed();
System.out.println("======end=======");
}
}
AopTestService.java
@Service
public class AopTestService {
@WillErase
public void test() {
}
}
AopTestController.java
@RestController
public class AopTestController {
@Autowired
private AopTestService aopTestService;
@GetMapping(value = "testaop")
public String testaop() {
aopTestService.test();
Class<? extends AopTestService> aClass = aopTestService.getClass();
Method[] methods = aClass.getMethods();
Optional<Method> first = Arrays.stream(methods)
.filter(method -> method.isAnnotationPresent(WillErase.class))
.findFirst();
System.out.println(first.isPresent());
return "";
}
}
当执行testaop的时候获取到的method确实是没结果。我们逐步debug,看下method[]中的内容:
method数组
一个简单的aoptestservice里面发现存在43个方法,去掉我们原本的
test(),toString(),hashCode()...
也不应该有这么多,仔细看都是cglib的enhancer给我们生成的,我们在看图中test()
方法的 annotations
是null的,然后大概能猜到是因为enhancer引起的,那再去验证下这个动态代理的service生成过程AopTestService
bingo!就是在生成这个代理类的时候test()方法上的注解被抹掉了,!-_-就不说过程了。需要参考
spring aop
初始流程。
结论:当存在切面的时候使用enhancer生成代理类那么注解会被抹掉,即便注解是@Inherited
注解。