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

hts6caw3  于 2023-10-15  发布在  Spring
关注(0)|答案(7)|浏览(211)

我有下面的注解。

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”值?
谢谢你,谢谢

ukxgm1gy

ukxgm1gy1#

您可以从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的MergedAnnotations的功能感兴趣,它是在5.2中引入的。

ryevplcw

ryevplcw2#

实际上,我认为我们可以通过另一种方式获得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可以是有效的变量名,因为params中的MyAnnotation已经指出了它应该是哪个注解。这里yourAnnotation仅用于检索注解示例。
如果你想传递更多的参数,你可以尝试args()
更多详情,请查看其官方doc。对于Annotation值,您可以搜索@Auditable

lpwwtiir

lpwwtiir3#

这也可以工作--你可以使用类的反射来获取注解信息。

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

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

只有当您的注解在运行时可用时,这才有效,您已经正确声明了。

@Retention(RetentionPolicy.RUNTIME)
zbwhf8kr

zbwhf8kr4#

***也解释了我是如何得到ClassLevel Annotations的。

但是,如果我之前使用了带有“*@Around(“execution(public * (..))&& @annotation(com.mycompany.MyAnnotation)”)"”的方法注解,则只能读取ClassLevel Annotations Values
我该怎么解决这个问题?如果ClassLevel Annotation被设置而不经过Method Execution,我如何触发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”的配置,我希望在其中接收“SwagerPackage”的值

@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)
gajydyqb

gajydyqb5#

使用AOP J/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;
    }
kxxlusnw

kxxlusnw6#

你可以简单地按照文档中的描述绑定方法。
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

  }
}
6kkfgxo0

6kkfgxo07#

Using AspectJ with Spring Applications aspectjweaver 1.8.5

为了计算方法的执行时间和使用ANOJ访问注解值,ANOJ是Java应用程序中横切关注点的强大框架,包括性能监视和方法级注解等方面。下面的示例用于为@RequestMapping注解创建度量执行时间的方面,并获取endpoint value及其执行时间沿着。

@Aspect
@Component
@org.springframework.context.annotation.EnableAspectJAutoProxy
public class EndpointTimeAspect {

    //@Around("execution(* com.myapp.resource.*.*(..) )")
    @Around("@annotation(org.springframework.web.bind.annotation.RequestMapping)")
    public Object logExecutionTime(ProceedingJoinPoint joinPoint) throws Throwable {
        long startTime = System.currentTimeMillis();
        
        Object result = joinPoint.proceed();
        
        long endTime = System.currentTimeMillis();
        long timeTaken = endTime - startTime;
        
        org.aspectj.lang.reflect.MethodSignature signature = (org.aspectj.lang.reflect.MethodSignature) joinPoint.getSignature();
        java.lang.reflect.Method method = signature.getMethod();
        Class<?> declaringClass = method.getDeclaringClass();
        
        org.springframework.web.bind.annotation.RequestMapping ann = 
                AnnotationUtils.findAnnotation(method, org.springframework.web.bind.annotation.RequestMapping.class);
        
        String[] value = ann.value();
        String path = "";
        for (String string : value) {
            path += string;
        }
        
        System.out.println("["+ signature +" ], Time taken for endpoint [ " +path +" ] : " + timeTaken + " ms");
        
        return result;
    }
}

AspectJ to calculate execution time

相关问题