我使用此自定义注释来记录执行时间,注释可以出现在所有公共方法都拥有它的方法或类中。一切正常,除非方法级别“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());
}
}
当我们使用OR'||'时希望了解这种行为有两个切入点。
班级
@LogExecutionTime
@Component
public class CleanUpService implements ICleanUpService { ... }
方法级别
@Scheduled(fixedDelay = 100)
@LogExecutionTime(false)
public void processMessageQueue() { ... }
答案 0 :(得分:1)
我来运行你的例子,并重现与你的相同的例子,当它来到运行时表达式同样奇怪,因为当您在类级别指定注释并且您编写此表达式时
@Around(" @within(logExecutionTime) || @annotation(logExecutionTime) ")
对于您的课程,分数评分将为真(您在joinPoint.getTarget().getClass().getAnnotations()
中注释的事件,)
现在,在绑定变量时,编译器会检查所有表达式@within(logExecutionTime)
与变量logExecutionTime和@annotation(logExecutionTime)
绑定到同一变量的表达式,如果方法是没有注释它将ge null,=>覆盖初始化,导致你提到的所有senarios。
尝试将此表达式设为@within(logExecutionTime) || @annotation(logExecutionTime) || @within(logExecutionTime)
并且你会得到变量not null,这证明了我所说的,最后@within(logExecutionTime)
覆盖了先例
这里的关键是应用于选择点切割匹配的逻辑在上下文绑定时不一样
现在当谈到AOP切入点时,你必须小心并按照他们提到here的春季团队的最佳实践来避免奇怪的运行结果
干杯
答案 1 :(得分:0)
这不起作用,甚至不用AspectJ编译器编译。也许在你的IDE和Spring AOP中你没有看到任何警告或错误,但我看到了:
ambiguous binding of parameter(s) logExecutionTime across '||' in pointcut
这意味着如果例如选择哪个注释则不清楚。类和方法都包含该批注的实例。正如错误信息所说,它是模棱两可的。但是不允许跨||
的模糊参数绑定。如果您尝试将来自不同“或”分支的值绑定到args()
列表中的单个参数,也会发生这种情况。
答案 2 :(得分:0)
我遇到了同样的问题。你想要的与Spring @Trantcriptional的行为完全相同(我的意思是,带有参数的类级别或方法级别注释)。我使用了你的解决方案,但是为了获得类级参数值(因为注释对象收到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();
}
让我们知道你是否有更清洁的解决方案!