当通过反射查看属于通过CGLIB代理的类的方法的注释时,我遇到了一种奇怪的行为。我们在Spring中使用CGLIB,如果我仅使用注释注释方法,它就可以正常工作(我可以通过对应的getAnnotations()
对象上的Method
方法检索注释)。如果我使用2个注释来注释方法(无论注释顺序如何),getAnnotations()
只返回null
。两个注释都有RetentionPolicy.RUNTIME
。
我读过CGLIB存在一些问题,但奇怪的是它只适用于一个注释,当我输入2个注释时它返回null。
有什么建议吗?
(使用Spring 3.0.5和CGLIB 2.2.2)
添加代码:
第一个注释是:
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface Produces {
ResultType[] value();
}
第二个注释是
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface JamonMonitored {
String type() default "";
String tag() default "";
}
代码块用于检查注释
Collection<Method> candidates = Collections2.filter(Arrays.asList(executorInstance.getClass().getMethods()), new Predicate<Method>() {
@Override
public boolean apply(Method input) {
return input.getAnnotation(Produces.class) != null;
}
});
if (candidates.isEmpty()) {
// throws exception
}
如果我使用@Produces和@JamonMonitored批注方法,getAnnotation(Produces.class)
始终为null
。
答案 0 :(得分:16)
CGLIB通过生成目标对象的类的子类来工作,并且该子类生成了委托给目标对象的方法。当您使用反射来查询代理对象的注释时,您要求在代理类上进行注释,而不是目标对象的类。
Spring必须自己进行大量的注释处理,以便在代理,超类,接口等方面进行导航。执行此操作的逻辑被封装并在org.springframework.core.annotation.AnnotationUtils
类中公开。在你的情况下,听起来你想要findAnnotation
utility method,即
@Override
public boolean apply(Method input) {
return AnnotationUtils.findAnnotation(input, Produces.class) != null;
}
答案 1 :(得分:1)
另一种选择是在注释定义中指定@Inherited。这将使注释出现在cglib生成的子类中。当然,在某些情况下,您不希望您的注释出现在“真实”子类中,因此这可能不是每个场景的选项,而且可以使用如skaffman所示的Spring助手