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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/27929965/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-11-02 12:38:32  来源:igfitidea点击:

Find method level custom annotation in a Spring context

javaspringspring-mvc

提问by kamoor

All I wanted to find out was "all the class/methods in Springbeans which are annotated as @Versioned".

我只想找出“ Springbean 中所有被注释为@Versioned的类/方法”。

I created my custom annotation as,

我创建了我的自定义注释,

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

This annotation works perfectlywhen I use Java reflection to find methods as:

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

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

But it does not work when I access Spring beans and try similar check:

但是当我访问 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
                }
            }
        }
    }
}

In fact, this code does find other annotations such as @RequestMapping. I am not sure what I am doing wrong with my custom annotation.

事实上,这段代码确实找到了其他注解,例如@RequestMapping。我不确定我的自定义注释做错了什么。

回答by owaism

Going through your code, I figured out that you are using Spring AOP with CGLIB Proxying. Due to which your classes (which have methods annotated with @Versioned) are being proxied.

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

I have tested this solution with your code base.

我已经用你的代码库测试了这个解决方案。

Use the following code, and it should resolve your issue. Look for more options below the code snippet:

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

@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
                }
            }
        }
    }
}

To detect a proxy class:

检测代理类:

  • For Spring AOP proxy using any proxying mechanism use org.springframework.aop.support.AopUtils#isAoPProxy
  • If you are proxying with Spring CGLIB (not via Spring AOP), use org.springframework.cglib.proxy.Proxy#isProxyClass
  • If you are proxying using JDK Proxy, use java.lang.reflect.Proxy#isProxyClass
  • 对于使用任何代理机制的 Spring AOP 代理,请使用 org.springframework.aop.support.AopUtils#isAoPProxy
  • 如果您使用 Spring CGLIB(不是通过 Spring AOP)进行代理,请使用 org.springframework.cglib.proxy.Proxy#isProxyClass
  • 如果您使用 JDK 代理进行代理,请使用 java.lang.reflect.Proxy#isProxyClass

I have just written one ifcondition which is sufficient in your case; but in case multiple proxying utilities are used, multiple if-elseconditions will have to be written based on the information above.

我刚刚写了一个if条件,对你的情况来说是充分的;但如果使用多个代理实用程序,if-else则必须根据上述信息编写多个条件。

回答by Angad

applicationContext.getBean(beanName).getClass()gives you the proxied class that Spring creates around your target class.

applicationContext.getBean(beanName).getClass()为您提供 Spring 在您的目标类周围创建的代理类。

What you want is to get hold of the target class, if any, from your Spring bean.

您想要的是从 Spring bean 中获取目标类(如果有)。

Spring provides a nice utility class for resolving this called AopUtils.class.

Spring 提供了一个很好的实用程序类来解决这个问题,称为 AopUtils.class。

Below is how you would use it:

以下是您将如何使用它:

for(String beanName: applicationContext.getBeanDefinitionNames()){
    Method[] methods = AopUtils.getTargetClass(applicationContext.getBean(beanName)).getDeclaredMethods();

    for(Method m: methods){
        if(m.isAnnotationPresent(Versioned.class){
        }
    }
}

Note that you will have to import the spring-aopMavendependency to get hold of the AopUtils class:

请注意,您必须导入spring-aopMaven依赖项才能获取 AopUtils 类:

<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-aop</artifactId>
    <version>${spring.version}</version>
</dependency>

回答by AH-64

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?
                }

            }
        }
    }
}