【问题标题】:How do I prevent Spring Boot AOP from removing type annotations?如何防止 Spring Boot AOP 删除类型注释?
【发布时间】:2020-04-21 18:43:57
【问题描述】:

我对 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注解都没有了。

示例元装饰类:

@Component
@GreetingsMeta(name = "Default", version = 1.0f)
public class DefaultGreetingsService implements IGreetingService {


    @Override
    public String message(String content) {
        return "Hello, " + content;
    }
} 

我应该如何排除故障?

【问题讨论】:

    标签: java spring-boot spring-aop


    【解决方案1】:

    如何防止 Spring Boot AOP 移除类型注解?

    Spring Boot 不会删除任何东西,但对于 Spring AOP 而言,它使用在运行时生成的动态代理,即带有事件挂钩(连接点)的子类或接口实现,用于通过切入点连接的方面建议代码。默认情况下,注解是不被继承的,所以这只是 JVM 的一个特性。

    子类从父类继承注解有一个例外:可以将元注解@Inherited添加到自己的注解类GreetingsMeta中。效果将是,如果您使用它注释任何类,所有子类(也由 Spring AOP 创建的动态代理)将继承该注释,并且您的原始代码应该按预期运行。

    所以在这种情况下,没有必要按照 JC Carrillo 的建议使用 AnnotationUtils。当然,他的方法也有效。它只是更复杂,因为AnnotationUtils 在内部使用了大量的反射魔法和大量的辅助类来计算结果。因此,我只会使用AnnotationUtils 在您不直接注释类但例如方法或接口,因为@Inherited 对它们没有影响,如文档所述。或者,如果您依赖于 Spring(或自己的)元注释(注释上的注释)的层次结构,并且您需要将它们中的信息全部合并为一个,AnnotationUtilsMergedAnnotations 是合适的。

    【讨论】:

      【解决方案2】:

      您可能想查看AnnotationUtils

      Method method = methodSignature.getMethod();
      GreetingsMeta greetingsMeta = AnnotationUtils.findAnnotation(method, GreetingsMeta.class);
      

      【讨论】:

        猜你喜欢
        • 2023-03-15
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2023-01-27
        • 1970-01-01
        • 2017-02-02
        相关资源
        最近更新 更多