9

通过反射查找属于通过 CGLIB 代理的类的方法的注释时,我遇到了一种奇怪的行为。我们在 Spring 中使用 CGLIB,如果我只使用注释对方法进行注释,则效果很好(我可以通过getAnnotations()对应Method对象上的方法检索注释)。如果我用 2 个注释来注释该方法(无论注释的顺序如何),getAnnotations()只需 return 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.

4

2 回答 2

18

CGLIB 通过生成目标对象类的子类来工作,并且该子类生成了委托给目标对象的方法。当您使用反射查询代理对象的注释时,您要求的是代理类的注释,而不是目标对象的类。

为了在代理、超类、接口等周围导航,Spring 必须自己进行大量注释处理。执行此操作的逻辑被封装并暴露在org.springframework.core.annotation.AnnotationUtils类中。在你的情况下,听起来你想要findAnnotation实用方法,即

@Override
public boolean apply(Method input) {
    return AnnotationUtils.findAnnotation(input, Produces.class) != null;
}
于 2012-01-25T16:00:18.883 回答
2

另一种选择是在注释定义中指定@Inherited。这将使注释甚至出现在 cglib 生成的子类中。当然,在某些情况下,您不希望您的注释出现在“真实”子类中,因此这可能不是每个场景的选项,而要走的路是使用 Spring 助手,如 skaffman 所示

于 2013-01-18T10:58:47.993 回答