在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
则必须根据以上信息编写多个条件。