如何防止 Spring Boot AOP 删除类型注释?
How do I prevent Spring Boot AOP from removing type annotations?
我对 Spring Boot 及其 AOP 风格还很陌生,但对使用其他语言和 AOP 框架进行编程并不陌生。我不确定如何解决这一挑战。
我有一个简单的元数据装饰器:
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface GreetingsMeta {
public float version() default 0;
public String name() default "";
}
依赖注入效果很好:
public GreetingController(List<IGreetingService> greetings) throws Exception {
this.greetings = new HashMap<>();
greetings.forEach(m -> {
Class<?> clazz = m.getClass();
if (clazz.isAnnotationPresent(GreetingsMeta.class)) {
GreetingsMeta[] s = clazz.getAnnotationsByType(GreetingsMeta.class);
this.greetings.put(s[0].name(), m);
}
});
}
直到我应用了标准日志方面:
@Aspect
@Component
public class LoggingAspect {
@Around("execution(* com.firm..*(..)))")
public Object profileAllMethods(ProceedingJoinPoint joinPoint) throws Throwable {
MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature();
String methodName = methodSignature.getName();
final StopWatch stopWatch = new StopWatch();
stopWatch.start();
Object result = joinPoint.proceed();
stopWatch.stop();
LogManager.getLogger(methodSignature.getDeclaringType())
.info(methodName + " " + (stopWatch.getTotalTimeSeconds() * 1000) + " µs");
return result;
}
}
然后annotationsData列表就变空了,连@Component注解都没有了。
元修饰样本 class:
@Component
@GreetingsMeta(name = "Default", version = 1.0f)
public class DefaultGreetingsService implements IGreetingService {
@Override
public String message(String content) {
return "Hello, " + content;
}
}
我应该如何排除故障?
您可能需要查看 AnnotationUtils
Method method = methodSignature.getMethod();
GreetingsMeta greetingsMeta = AnnotationUtils.findAnnotation(method, GreetingsMeta.class);
How do I prevent Spring Boot AOP from removing type annotations?
Spring 引导不会删除任何内容,但对于 Spring AOP 使用在 运行 时间期间生成的动态代理,即 subclasses 或带有事件的接口实现通过切入点连接的方面建议代码的钩子(连接点)。默认情况下,注释不会被继承,所以这只是一个 JVM 特性。
子classes从父classes继承注解有一个例外:您可以将元注解@Inherited
添加到您自己的注解classGreetingsMeta
。效果是,如果你用它注释任何 class,所有子 classes(也是由 Spring AOP 创建的动态代理)将继承注释并且你的原始代码应该 运行 符合预期。
所以在这种情况下,不需要使用 JC Carrillo 建议的 AnnotationUtils
。当然,他的方法也很管用。它只是更复杂,因为 AnnotationUtils
在内部使用了很多反射魔法和很多助手 classes 来计算结果。因此,我只会在您不直接注释 class 的情况下使用 AnnotationUtils
,例如方法或接口,因为 @Inherited
对它们没有影响,如文档所述。或者,如果您依赖于 Spring(或自己的)元注释(annotations on annotations)的层次结构,并且您需要从它们中获取信息全部合并为一个,则 AnnotationUtils
或 MergedAnnotations
是合适的.
我对 Spring Boot 及其 AOP 风格还很陌生,但对使用其他语言和 AOP 框架进行编程并不陌生。我不确定如何解决这一挑战。
我有一个简单的元数据装饰器:
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface GreetingsMeta {
public float version() default 0;
public String name() default "";
}
依赖注入效果很好:
public GreetingController(List<IGreetingService> greetings) throws Exception {
this.greetings = new HashMap<>();
greetings.forEach(m -> {
Class<?> clazz = m.getClass();
if (clazz.isAnnotationPresent(GreetingsMeta.class)) {
GreetingsMeta[] s = clazz.getAnnotationsByType(GreetingsMeta.class);
this.greetings.put(s[0].name(), m);
}
});
}
直到我应用了标准日志方面:
@Aspect
@Component
public class LoggingAspect {
@Around("execution(* com.firm..*(..)))")
public Object profileAllMethods(ProceedingJoinPoint joinPoint) throws Throwable {
MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature();
String methodName = methodSignature.getName();
final StopWatch stopWatch = new StopWatch();
stopWatch.start();
Object result = joinPoint.proceed();
stopWatch.stop();
LogManager.getLogger(methodSignature.getDeclaringType())
.info(methodName + " " + (stopWatch.getTotalTimeSeconds() * 1000) + " µs");
return result;
}
}
然后annotationsData列表就变空了,连@Component注解都没有了。
元修饰样本 class:
@Component
@GreetingsMeta(name = "Default", version = 1.0f)
public class DefaultGreetingsService implements IGreetingService {
@Override
public String message(String content) {
return "Hello, " + content;
}
}
我应该如何排除故障?
您可能需要查看 AnnotationUtils
Method method = methodSignature.getMethod();
GreetingsMeta greetingsMeta = AnnotationUtils.findAnnotation(method, GreetingsMeta.class);
How do I prevent Spring Boot AOP from removing type annotations?
Spring 引导不会删除任何内容,但对于 Spring AOP 使用在 运行 时间期间生成的动态代理,即 subclasses 或带有事件的接口实现通过切入点连接的方面建议代码的钩子(连接点)。默认情况下,注释不会被继承,所以这只是一个 JVM 特性。
子classes从父classes继承注解有一个例外:您可以将元注解@Inherited
添加到您自己的注解classGreetingsMeta
。效果是,如果你用它注释任何 class,所有子 classes(也是由 Spring AOP 创建的动态代理)将继承注释并且你的原始代码应该 运行 符合预期。
所以在这种情况下,不需要使用 JC Carrillo 建议的 AnnotationUtils
。当然,他的方法也很管用。它只是更复杂,因为 AnnotationUtils
在内部使用了很多反射魔法和很多助手 classes 来计算结果。因此,我只会在您不直接注释 class 的情况下使用 AnnotationUtils
,例如方法或接口,因为 @Inherited
对它们没有影响,如文档所述。或者,如果您依赖于 Spring(或自己的)元注释(annotations on annotations)的层次结构,并且您需要从它们中获取信息全部合并为一个,则 AnnotationUtils
或 MergedAnnotations
是合适的.