在 Spring 上下文中查找方法级别自定义注释
Find method level custom annotation in a Spring context
我只想知道 "all the class/methods in Spring beans which are annotated as @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 beans 并尝试类似的检查时它不起作用:
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等其他注解。我不确定我的自定义注释做错了什么。
applicationContext.getBean(beanName).getClass()
为您提供 Spring 在您的目标 class 周围创建的代理 class。
你想要的是从你的 Spring bean 中获取目标 class,如果有的话。
Spring 提供了一个很好的工具 class 来解决这个叫做 AopUtils.class.
下面是您将如何使用它:
for(String beanName: applicationContext.getBeanDefinitionNames()){
Method[] methods = AopUtils.getTargetClass(applicationContext.getBean(beanName)).getDeclaredMethods();
for(Method m: methods){
if(m.isAnnotationPresent(Versioned.class){
}
}
}
请注意,您必须导入 spring-aop
Maven 依赖项才能获取 AopUtils class:
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aop</artifactId>
<version>${spring.version}</version>
</dependency>
通过您的代码,我发现您正在使用 Spring AOP 和 CGLIB 代理。因此,您的 classes(具有用 @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
}
}
}
}
}
检测代理 class:
- 对于使用任何代理机制的 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
条件。
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
for (String beanName : applicationContext.getBeanDefinitionNames()) {
Object obj = applicationContext.getBean(beanName);
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(Transactional.class)) {
Transactional transactional = m.getAnnotation(Transactional.class);
Class<? extends Throwable>[] value = transactional.rollbackFor();
if (value == null){
// help !!!
// If value is null, I want to set a value for him like Exception.class How can I modify it?
}
}
}
}
}
我只想知道 "all the class/methods in Spring beans which are annotated as @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 beans 并尝试类似的检查时它不起作用:
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等其他注解。我不确定我的自定义注释做错了什么。
applicationContext.getBean(beanName).getClass()
为您提供 Spring 在您的目标 class 周围创建的代理 class。
你想要的是从你的 Spring bean 中获取目标 class,如果有的话。
Spring 提供了一个很好的工具 class 来解决这个叫做 AopUtils.class.
下面是您将如何使用它:
for(String beanName: applicationContext.getBeanDefinitionNames()){
Method[] methods = AopUtils.getTargetClass(applicationContext.getBean(beanName)).getDeclaredMethods();
for(Method m: methods){
if(m.isAnnotationPresent(Versioned.class){
}
}
}
请注意,您必须导入 spring-aop
Maven 依赖项才能获取 AopUtils class:
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aop</artifactId>
<version>${spring.version}</version>
</dependency>
通过您的代码,我发现您正在使用 Spring AOP 和 CGLIB 代理。因此,您的 classes(具有用 @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
}
}
}
}
}
检测代理 class:
- 对于使用任何代理机制的 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
条件。
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
for (String beanName : applicationContext.getBeanDefinitionNames()) {
Object obj = applicationContext.getBean(beanName);
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(Transactional.class)) {
Transactional transactional = m.getAnnotation(Transactional.class);
Class<? extends Throwable>[] value = transactional.rollbackFor();
if (value == null){
// help !!!
// If value is null, I want to set a value for him like Exception.class How can I modify it?
}
}
}
}
}