弹簧AOP自定义注释,用注释参数使无效



我正在使用此自定义注释来记录执行时间,可以在所有公共方法拥有的方法或类上存在注释。一切正常,除了方法级别" logexecutiontime logexecutiontime"之外。这会抛出NPE。

@Around("@annotation(logExecutionTime) || @within(logExecutionTime)")
public Object logExecutionTime(ProceedingJoinPoint joinPoint, LogExecutionTime logExecutionTime) throws Throwable {
    final Logger logger = LoggerFactory.getLogger(joinPoint.getTarget().getClass());
    final String name = joinPoint.toShortString();
    final StopWatch stopWatch = new StopWatch(name);
    stopWatch.start(name);
    try {
      return joinPoint.proceed();
    } finally {
      stopWatch.stop();
      if (logExecutionTime.value()) {
        logger.info(joinPoint.getSignature().getName() + ".time=", stopWatch.getTotalTimeSeconds());
      }
    }
  }

如果我扭转了订单 -

@Around("@within(logExecutionTime) || @annotation(logExecutionTime)")

行为逆转,我在方法级别获得了一个有效的对象,而在类级别注释的方法为null。

我通过使用2种明确的方法并分开两个

来解决这个问题。
@Around("@within(logExecutionTime)")
public Object logExecutionTimeClassLevel(ProceedingJoinPoint joinPoint, LogExecutionTime logExecutionTime) throws Throwable {
    return logExecutionTimeMethodLevel(joinPoint, logExecutionTime);
  }
@Around("@annotation(logExecutionTime)")
public Object logExecutionTimeMethodLevel(ProceedingJoinPoint joinPoint, LogExecutionTime logExecutionTime) throws Throwable {
    final Logger logger = LoggerFactory.getLogger(joinPoint.getTarget().getClass());
    final String name = joinPoint.toShortString();
    final StopWatch stopWatch = new StopWatch(name);
    stopWatch.start(name);
    try {
      return joinPoint.proceed();
    } finally {
      stopWatch.stop();
      if (logExecutionTime.value()) {
        logger.info(joinPoint.getSignature().getName() + ".time=", stopWatch.getTotalTimeMillis());
      }
    }

当我们使用或'||'时,希望理解这种行为带有两个点数。

类级

@LogExecutionTime
@Component
public class CleanUpService implements ICleanUpService { ... }

方法级

@Scheduled(fixedDelay = 100)
@LogExecutionTime(false)
public void processMessageQueue() { ... }

我来运行您的示例,并重现与您的示例相同的示例,当涉及到运行时表达式是相同的怪异时/p>

@Around(" @within(logExecutionTime) || @annotation(logExecutionTime) ")

cut cut将对您的班级进行评估(事件您的注释在joinPoint.getTarget().getClass().getAnnotations()中可用(

(

现在,当涉及到变量时,编译器检查您的所有表达式,这意味着将@within(logExecutionTime)绑定到变量logexecution Time和@annotation(logExecutionTime) 与同一变量>>覆盖最初的,这是您提到的所有senarios。

尝试放置此表达式@within(logExecutionTime) || @annotation(logExecutionTime) || @within(logExecutionTime)而且您将使您的变量不是null证明我所说的,最后@within(logExecutionTime)覆盖了什么先例

这里的关键是,逻辑应用于上下文结合

时,选择点剪切匹配不相同

现在,当涉及到aop cut时,您必须小心并遵循最佳练习,因为他们在这里提到的春季团队以避免怪异的运行时结果

欢呼

这是无法工作的,它甚至不会与ActectJ编译器进行编译。也许在您的IDE和春季AOP中,您看不到任何警告或错误,但我看到:

ambiguous binding of parameter(s) logExecutionTime across '||' in pointcut

这意味着尚不清楚如果例如,应该选择哪个注释。类和方法都包含该注释的实例。正如错误消息所说,这是模棱两可的。但是不允许跨||的模棱两可的参数绑定。如果您尝试将不同的"或"分支与args()列表中的单个参数绑定到单个参数时,它们也可能发生。

我也有同样的问题。您想要的与Spring @Transcriptional的行为完全相同(我的意思是,使用参数的类级或方法级别注释(。我使用了您的解决方案,但要获取类级别参数值(作为接收到null的注释对象(,我使用了反射。我知道这是一个肮脏的解决方案!但是我尝试了其他解决方案,找不到!

她是完整的代码。这将调用咨询代码的注释在类或方法上使用。如果将注释放在(类和方法(上,则该方法采用优先级。

@Aspect
@Configurable
@Component
public class DynamicValueAspect {

    @Around(" @within(dynamicValueAnnotation) || @annotation(dynamicValueAnnotation))")
    public Object process(ProceedingJoinPoint joinPoint, DynamicValue dynamicValueAnnotation) throws Throwable {
        String annotationParameter;
        if (dynamicValueAnnotation == null) { //class level annotation
            annotationParameter = extractClassLevelAnnotationParameterValue(joinPoint);
        } else {
            annotationParameter = dynamicValueAnnotation.myAnnotationParameter();
        }
        System.out.println("    " + annotationParameter);//get the annotation parameter value
        return joinPoint.proceed();
    }
    private String extractClassLevelAnnotationParameterValue(ProceedingJoinPoint joinPoint) {
        Annotation[] classAnnotations = joinPoint.getTarget().getClass().getAnnotations();
        for (Annotation annotation : classAnnotations) {
            if (annotation.annotationType() == DynamicValue.class) {
                return ((DynamicValue) annotation).myAnnotationParameter();
            }
        }
        throw new RuntimeException("No DynamicValue value annotation was found");
    }
}
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD, ElementType.TYPE})
public @interface DynamicValue {
    String myAnnotationParameter();
}

让我们知道您是否有更清洁的解决方案!

当您注释一类带注释的方法和方法时出现解决方法的问题,从而触发了两个。

防止其声明班级建议为:

@Around("!@annotation(LogExecutionTime) && @within(logExecutionTime)")

最新更新