在Spring上下文中查找方法级别的自定义注释


问题内容

我想发现的就是“ Spring
bean中所有标注为@Versioned 的类/方法”。

我将自定义注释创建为

@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Versioned {
    .....
}

当我使用Java反射来查找方法时,此批注 非常有效

for(Method m: obj.getClass().getMethods()){
    if(m.isAnnotationPresent(Versioned.class)){
        .... // Do something
    }

但是当我访问Spring bean并尝试类似的检查时,它不起作用:

public class VersionScanner implements ApplicationContextAware{
    public void setApplicationContext(ApplicationContext applicationContext){
        for(String beanName: applicationContext.getBeanDefinitionNames()){
            for(Method m: applicationContext.getBean(beanName).getClass().getDeclaredMethods()){
                if(m.isAnnotationPresent(Versioned.class){
                    // This is not WORKING as expected for any beans with method annotated
                }
            }
        }
    }
}

实际上,此代码确实会找到其他注释,例如@RequestMapping。我不确定自己的自定义注释在做什么错。


问题答案:

通过您的代码,我发现您正在将Spring AOP与CGLIB代理一起使用。因此,您的类(使用注释的方法@Versioned)将被代理。

我已经用您的代码库测试了该解决方案。

使用以下代码,它应该可以解决您的问题。在代码段下方查找更多选项:

@Configuration
public class VersionScanner implements ApplicationContextAware {

    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {

        for (String beanName : applicationContext.getBeanDefinitionNames()) {
            Object obj = applicationContext.getBean(beanName);
            /*
             * As you are using AOP check for AOP proxying. If you are proxying with Spring CGLIB (not via Spring AOP)
             * Use org.springframework.cglib.proxy.Proxy#isProxyClass to detect proxy If you are proxying using JDK
             * Proxy use java.lang.reflect.Proxy#isProxyClass
             */
            Class<?> objClz = obj.getClass();
            if (org.springframework.aop.support.AopUtils.isAopProxy(obj)) {

                objClz = org.springframework.aop.support.AopUtils.getTargetClass(obj);
            }

            for (Method m : objClz.getDeclaredMethods()) {
                if (m.isAnnotationPresent(Versioned.class)) {
                    //Should give you expected results
                }
            }
        }
    }
}

要检测代理类:

  • 对于使用任何代理机制的Spring AOP代理,请使用 org.springframework.aop.support.AopUtils#isAoPProxy
  • 如果要通过Spring CGLIB代理(而不是通过Spring AOP),请使用 org.springframework.cglib.proxy.Proxy#isProxyClass
  • 如果要使用JDK代理进行代理,请使用 java.lang.reflect.Proxy#isProxyClass

我刚刚写了一个if足以满足您情况的条件;但是如果使用多个代理实用程序,if-else则必须根据以上信息编写多个条件。