Как получить значение аннотации метода из ProceedingJoinPoint?
У меня ниже аннотации.
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){
}
}
В вышеприведенном классе пропуская " ABC" с помощью @MyAnnotation.
Теперь, как я могу получить доступ к значению ABC "в процедуре метода класса SomeAspect.java?
Спасибо!
Ответы
Ответ 1
Вы можете получить подпись из 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);
}
Но сначала вы должны добавить атрибут аннотации. В вашем примере кода его нет, например
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface MyAnnotation {
String value();
}
Тогда вы можете получить к нему доступ
MyAnnotation myAnnotation = method.getAnnotation(MyAnnotation.class);
String value = myAnnotation.value();
EDIT
Как получить значение, если у меня есть @MyAnnotation ("ABC") на уровне класса?
Class
также является AnnotatedElement
, поэтому вы можете получить его так же, как и из Method
. Например. Аннотация к классу объявления метода может быть получена с помощью
Method method = ...;
Class<?> declaringClass = method.getDeclaringClass();
MyAnnotation myAnnotation = declaringClass.getAnnotation(MyAnnotation.class)
Поскольку вы используете пружину, вы также можете использовать пружину AnnotationUtils.findAnnotation(..)
. Он ищет аннотацию, как spring. Например. также изучаем методы суперкласса и интерфейса и т.д.
MyAnnotation foundAnnotation = AnnotationUtils.findAnnotation(method, MyAnnotation.class);
Ответ 2
На самом деле я думаю, что мы можем получить 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
может быть допустимым именем переменной, поскольку MyAnnotation
в параметрах уже указывает, какой аннотацией она должна быть. Здесь yourAnnotation
используется только для извлечения экземпляра аннотации.
Если вы хотите передать больше параметров, попробуйте args()
.
Для получения более подробной информации, пожалуйста, проверьте его официальный документ. По значению аннотации вы можете просто выполнить поиск @Auditable
.
Ответ 3
Это также работает. Вы можете получить информацию об аннотации, используя отражение в классе.
Annotation anno = MyClass.class.getAnnotation(MyAnnotation.class);
или
Annotation anno = MyClass.class.getDeclaredMethod("somethod").getAnnotation(MyAnnotation.class);
Это работает, только если ваша аннотация доступна во время выполнения, которую вы заявили правильно.
@Retention(RetentionPolicy.RUNTIME)
Ответ 4
Пример Рене уводит меня далеко. Также объяснение, как я получаю аннотации ClassLevel.
Но тогда я могу читать только значения аннотаций ClassLevel, если я ранее использовал аннотацию метода с "* @Around (" выполнение (public * (..)) && @annotation (com.mycompany.MyAnnotation) ")" "
Как я могу обойти это? Как я могу активировать аспект, если аннотация 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()? Поскольку класс Application.class не известен SwaggerConfiguration (Swagger поместите его в отдельную библиотеку), я не могу использовать простые отражения, такие как
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;
}