【问题标题】:How to get a method's annotation value from a ProceedingJoinPoint?如何从 ProceedingJoinPoint 获取方法的注释值?
【发布时间】:2014-02-12 02:11:25
【问题描述】:

我有以下注释。

MyAnnotation.java

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface MyAnnotation {

}

SomeAspect.java

public class SomeAspect{

 @Around("execution(public * *(..)) && @annotation(com.mycompany.MyAnnotation)")
    public Object procede(ProceedingJoinPoint call) throws Throwable {

  //Some logic

}

}

SomeOther.java

public class SomeOther{

@MyAnnotation("ABC") 
public String someMethod(String name){


}


}

在上面的课程中,我在 @MyAnnotation 中传递了“ABC”。 现在如何在 SomeAspect.java 类的 procede 方法中访问“ABC”值?

谢谢!

【问题讨论】:

    标签: java spring spring-aop spring-3 java-ee-7


    【解决方案1】:

    您可以从ProceedingJoinPoint 获取Signature,如果是方法调用,只需将其转换为MethodSignature

    @Around("execution(public * *(..)) && @annotation(com.mycompany.MyAnnotation)")
    public Object procede(ProceedingJoinPoint call) throws Throwable {
        MethodSignature signature = (MethodSignature) call.getSignature();
        Method method = signature.getMethod();
    
        MyAnnotation myAnnotation = method.getAnnotation(MyAnnotation.class);
    }
    

    但是你应该首先添加一个注解属性。您的示例代码没有,例如

    @Target(ElementType.METHOD)
    @Retention(RetentionPolicy.RUNTIME)
    public @interface MyAnnotation {
    
        String value();
    }
    

    然后就可以访问了

    MyAnnotation myAnnotation = method.getAnnotation(MyAnnotation.class);
    String value = myAnnotation.value();
    

    编辑

    如果我在班级级别有@MyAnnotation("ABC"),如何获得价值?

    Class 也是 AnnotatedElement,因此您可以通过与 Method 相同的方式获取它。例如。方法的声明类的注解可以使用

     Method method = ...;
     Class<?> declaringClass = method.getDeclaringClass();
     MyAnnotation myAnnotation = declaringClass.getAnnotation(MyAnnotation.class)
    

    由于您使用的是 spring,您可能还想使用 spring 的AnnotationUtils.findAnnotation(..)。它像 spring 一样搜索注解。例如。还要查看超类和接口方法等。

     MyAnnotation foundAnnotation = AnnotationUtils.findAnnotation(method, MyAnnotation.class);
    

    编辑

    您可能还对 Spring 5.2 中引入的 MergedAnnotations 的功能感兴趣。

    【讨论】:

    • @user755806 您的注释示例尚未定义属性。我更新了我的答案,但我建议你阅读docs.oracle.com/javase/tutorial/java/annotations
    • 有没有办法改变该注释的值?
    • 哇,谢谢。我整天都在为此苦苦挣扎。谢谢!
    【解决方案2】:

    实际上我认为我们可以通过另一种方式获得value,而不是仅仅从ProceedingJoinPoint,这肯定需要我们使用reflection

    直接使用注解试试如下:在advice params中添加com.mycompany.MyAnnotation yourAnnotation,在@Around中添加@annotation(yourAnnotation)

    @Around("execution(public * *(..)) && @annotation(yourAnnotation)")
    public Object procede(ProceedingJoinPoint pjp, com.mycompany.MyAnnotation yourAnnotation) {
        ...
        yourAnnotation.value(); // get your annotation value directly;
        ...
    }
    

    com.mycompany.MyAnnotation 在建议参数中就像在

    中一样工作
    @Around("execution(public * *(..)) && @annotation(com.mycompany.MyAnnotation)")
    

    yourAnnotation 可以是有效的变量名,因为参数中的MyAnnotation 已经指出它应该是哪个注释。这里yourAnnotation仅用于检索注解实例。

    如果你想传递更多参数,你可以试试args()

    更多详情请查看官方doc。对于 Annotation 值,您只需搜索 @Auditable

    【讨论】:

    • 我认为这应该是公认的答案,因为它更干净且有记录的方式:docs.spring.io/spring/docs/4.3.15.RELEASE/…
    • 我同意(应该被接受的答案),这绝对是要走的路。接受的答案虽然正确,但非常笨拙。
    • 这适用于普通的 AspectJ 还是仅适用于 Spring-AOP?
    • @JakubBochenski 据我所知,Spring AOP 是建立在 AspectJ 之上的,所以基本上如果 Spring AOP 能做到这一点,AspectJ 应该以某种方式支持它。但我自己没有尝试过;p
    • 正如上面其他用户所提到的,接受的答案有效,但我认为这应该是接受的答案,因为它直截了当且正式记录在案,正好在本节中:docs.spring.io/spring/docs/4.3.15.RELEASE/…
    【解决方案3】:

    这也有效 - 您可以使用类上的反射来获取注释信息。

    Annotation anno = MyClass.class.getAnnotation(MyAnnotation.class);
    

    或者

    Annotation anno = MyClass.class.getDeclaredMethod("somethod").getAnnotation(MyAnnotation.class);
    

    仅当您的注解在运行时可用且您已正确声明时才有效。

    @Retention(RetentionPolicy.RUNTIME)
    

    【讨论】:

    • 你用的是哪个Annotation类,不止一个
    【解决方案4】:

    René 的 例子让我走得很远。还有我如何获得 ClassLevel Annotations 的解释。

    但是,如果我之前使用了带有“*@Around(”execution(public * (..)) && @annotation(com.mycompany.MyAnnotation)”的方法注释,那么我只能读取 ClassLevel Annotations Values )""

    我该如何解决这个问题?如果没有通过方法执行设置了 ClassLevel Annotation,我如何触发 Aspect?

    我想写一个 ClassLevel Annotation 之类的

    @Documented
    @Retention(RetentionPolicy.RUNTIME)
    @Target(value = { ElementType.METHOD, ElementType.TYPE })
    @EnableSwagger2
    @Import(SwaggerConfiguration.class)
    public @interface EnableSwaggerApi {
        String controllerPackage() default "foo.bar.ctrl";
    }
    

    它正在导入关于“SwaggerConfiguration”的配置,我想在其中接收“controllerPackage”的值

    @Aspect
    public class SwaggerConfiguration {
    
        @Value("${tom.swagger.controller.package:foo.bar.notset}")
        private String  controllerPackage;
    
        @Value("${tom.swagger.api.version:1.0.0}")
        private String  apiVersion;
    
        @Value("${spring.application.name:MyApplication}")
        private String  applicationName;
    
        @Around("execution(public * *(..)) && @annotation(EnableSwaggerApi)")
        public void procede(ProceedingJoinPoint call) throws Throwable {
            MethodSignature signature = (MethodSignature) call.getSignature();
            Method method = signature.getMethod();
    
            Class<?> declaringClass = method.getDeclaringClass();
            EnableSwaggerApi myAnnotation = declaringClass.getAnnotation(EnableSwaggerApi.class);
            System.err.println("1 -> " + myAnnotation.controllerPackage());  // -> tko.backend.spring.ctrl
    
            myAnnotation = method.getAnnotation(EnableSwaggerApi.class);
            System.err.println("2 -> " + myAnnotation.controllerPackage()); // -> tko.backend.spring.SOMEOTHERSTUFF
    
    
            // THIS WORKS, BUT JUST IF I USE THE @EnableSwaggerApi ON SOME METHOD!
            // NOT ON CLASS
    
        }
    
        @Bean
        public Docket swaggerApi() {
            return new Docket(DocumentationType.SWAGGER_2)
                    .select()
                    .apis(RequestHandlerSelectors.basePackage("controllerPackage"))
                    .paths(PathSelectors.any())
                    .build()
                    .apiInfo(new ApiInfoBuilder().version(apiVersion).title(applicationName).description("Documentation " + applicationName + " API v" + apiVersion)
                            .build());
        }
    
        @Bean
        public CorsFilter corsFilter() {
            final UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
            final CorsConfiguration config = new CorsConfiguration();
            config.setAllowCredentials(true);
            config.addAllowedOrigin("*");
            config.addAllowedHeader("*");
            config.addAllowedMethod("*");
            source.registerCorsConfiguration("/v2/api-docs", config);
            return new CorsFilter(source);
        }
    }
    
    
    
    
    
    @EnableSwaggerApi(controllerPackage="tko.backend.spring.ctrl")
    public class Application extends SpringBootServletInitializer {
    
        public static void main(String[] args) {
            SpringApplication.run(Application.class, args);
        }
    
        @Override
        protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
            return application.sources(Application.class, Initializer.class);
        }
    
    
        @Bean
        @EnableSwaggerApi(controllerPackage="tko.backend.spring.SOMEOTHERSTUFF")
        public String initSwagger() {
            return "some dummy";
        }
    
    }
    

    我怎样才能去掉 initSwagger() 上的注释?由于 Application.class 不知道 SwaggerConfiguration (Swagger Stuff 它在一个单独的库中)我不能使用像

    这样的简单反射
    Application.class.getAnnotation(EnableSwaggerApi.class)
    

    【讨论】:

      【解决方案5】:

      使用 AspectJ/AOP 查找方法注释和类级别注释的工作代码

         @Around("execution(* com.first.test.controller..*(..)))")
          public Object profileAllMethods(ProceedingJoinPoint proceedingJoinPoint) throws Throwable
          {
              MethodSignature methodSignature = (MethodSignature) proceedingJoinPoint.getSignature();
      
              java.lang.reflect.Method method = methodSignature.getMethod();
      
        Annotation []methodAnnotations =  method.getDeclaredAnnotations();
              System.out.println("==============="+methodAnnotations[0].toString());
      
              Annotation []classAnnotations = proceedingJoinPoint.getTarget().getClass().getAnnotations();
      
              System.out.println("===Class Annotation : "+classAnnotations[1].toString());
             Object result = proceedingJoinPoint.proceed();
              return result;
          }
      

      【讨论】:

        【解决方案6】:

        您可以按照docs 中的说明简单地绑定方法。

        MyAnnotation.java

        @Target(ElementType.METHOD)
        @Retention(RetentionPolicy.RUNTIME)
        public @interface MyAnnotation {
        
        }
        

        SomeAspect.java

        public class SomeAspect{
        
         @Around("execution(public * *(..)) && @annotation(myAnnotation)")
            public Object procede(ProceedingJoinPoint call, MyAnnotation myAnnotation) throws Throwable {
        
          //Some logic
        
          }
        }
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2023-03-21
          • 2011-08-08
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多