如何从ProceedingJoinPoint获取方法的注释值?

时间:2014-01-22 06:32:43

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

我有以下注释。

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 ”值?

谢谢!

6 个答案:

答案 0 :(得分:93)

您可以从Signature获取ProceedingJoinPoint,如果是方法调用,只需将其投放到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);
}

但是你应该首先添加一个注释属性。您的示例代码没有,例如<​​/ p>

@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) 。例如。可以使用

获取方法声明类的注释
 MyAnnotation foundAnnotation = AnnotationUtils.findAnnotation(method, MyAnnotation.class);

正如你使用的是春天,你可能也想使用春天的AnnotationUtils.findAnnotation(..)。它会像spring一样搜索注释。例如。还要查看超类和接口方法等。

{{1}}

答案 1 :(得分:8)

实际上我认为我们可以以另一种方式获得value,而不仅仅是来自 ProceedingJoinPoint ,这肯定会要求我们使用reflection

请直接使用注释尝试以下操作:在com.mycompany.MyAnnotation yourAnnotation中添加advice params,在@annotation(yourAnnotation)中添加@Around

@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可以是有效的变量名,因为params中的MyAnnotation已经指出它应该是哪个注释。这里yourAnnotation仅用于检索注释实例。

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

有关详细信息,请查看其官方doc。对于注释值,您只需搜索@Auditable即可。

答案 2 :(得分:3)

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

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

或者

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

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

@Retention(RetentionPolicy.RUNTIME)

答案 3 :(得分:0)

René的例子使我走了很长一段路。也是我如何获得ClassLevel注释的说明。

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

我该如何解决?如果设置了ClassLevel注释而不进行方法执行,如何触发方面?

我想写一个像这样的ClassLevel注释

@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()上的注释?由于 SwaggerConfiguration 不知道 Application.class (Swagger Stuff位于单独的库中),我不能使用

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

答案 4 :(得分:0)

使用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;
    }

答案 5 :(得分:0)

您可以简单地按照 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

  }
}