如何解决Spring Boot中的类级别和方法级别的注释方面NullPointerException
当我想为@Transactional
这样的注解创建方面时,我正面临一个有趣的问题。
这是控制器和注释:
@RestController
@SimpleAnnotation
public class HelloController{
private static final Logger LOGGER = LoggerFactory.getLogger(HelloController.class);
@GetMapping("/hello")
@SimpleAnnotation(isAllowed=true)
public String helloController(){
final String methodName = "helloController";
callAnotherMerhod();
LOGGER.info("HelloController for method : {}",methodName);
return "Hello";
}
private void callAnotherMethod(){
}
}
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD,ElementType.TYPE})
public @interface SimpleAnnotation {
boolean isAllowed() default false;
}
在这里注意该注释:
@Aspect
@Component
public class SimpleAspect {
private static final Logger LOGGER = LoggerFactory.getLogger(SimpleAspect.class);
@Around(value = "@within(simpleAnnotation) || @annotation(simpleAnnotation)",argNames = "simpleAnnotation")
public Object simpleAnnotation(ProceedingJoinPoint proceedingJoinPoint,SimpleAnnotation simpleAnnotation) throws Throwable{
LOGGER.info("Simple annotation value: {},ASPECT-LOG {}",simpleAnnotation.isAllowed(),proceedingJoinPoint.getSignature().getName());
return proceedingJoinPoint.proceed();
}
}
当我运行该应用程序并点击http:// localhost:8080 / hello时,一切都很好:
2020-11-09 11:36:48.230 INFO 8479 --- [nio-8080-exec-1] c.s.springaop.aspects.SimpleAspect : Simple annotation value: true,ASPECT-LOG helloController
2020-11-09 11:36:48.246 INFO 8479 --- [nio-8080-exec-1] c.s.s.controller.HelloController : HelloController for method : helloController
@GetMapping("/hello")
public String helloController(){
final String methodName = "helloController";
callAnotherMethod();
LOGGER.info("HelloController for method : {}",methodName);
return "Hello";
}
然后simpleAnnotation
参数为空,并且Aspect方法抛出NullPointerException。
之后,我更改了如下方面的顺序,它开始起作用:
@Around(value = " @annotation(simpleAnnotation) || @within(simpleAnnotation)",argNames = "simpleAnnotation")
但是,在这种情况下,如果我在类级别上删除注释,而仅将方法级别放进去,那么我将面临相同的NPE。
我认为,某种程度上,条件会覆盖这些值。
@Around(value = "@within(simpleAnnotation) || @annotation(simpleAnnotation) || @within(simpleAnnotation)",argNames = "simpleAnnotation")
编辑:此解决方案也不起作用。如果我在类和方法级别上都具有注释,并且假设类级别的注释值是false,而方法的级别是true,则那么注释值将是false 。
解决方法
由于||
,您的参数绑定是模棱两可的,因为它是一个(非排他的)OR而不是XOR,这意味着两个条件可能同时成立。想象一下,类和方法都有注释。应该绑定哪一个?
另请参阅this answer。
即就像R.G所说的那样,您要对方法和类级注释使用两个单独的切入点和建议。您仍然可以将重复的代码分解到方面内部的一个辅助方法中,并从两个建议方法中调用它。
,要变通解决NPE,您可以将切入点指示符(@within
和@annotation
)重构为同一方面的两种不同的建议方法。
基于isAllowed
值进行处理的逻辑可以保存在一个通用方法中,并可以从两种建议方法中调用。
为了说明:
@Aspect
@Component
public class SimpleAspect {
@Around(value = "@annotation(simpleAnnotation) && !@within(my.package.SimpleAnnotation)",argNames = "simpleAnnotation")
public Object simpleAnnotationOnMethod(ProceedingJoinPoint proceedingJoinPoint,SimpleAnnotation simpleAnnotation)
throws Throwable {
System.out.println("Simple annotation value:" + simpleAnnotation.isAllowed() + ",ASPECT-LOG :"
+ proceedingJoinPoint.getSignature().getName());
process(simpleAnnotation);
return proceedingJoinPoint.proceed();
}
@Around(value = "@within(simpleAnnotation)",argNames = "simpleAnnotation")
public Object simpleAnnotationOnType(ProceedingJoinPoint proceedingJoinPoint,ASPECT-LOG :"
+ proceedingJoinPoint.getSignature().getName());
process(simpleAnnotation);
return proceedingJoinPoint.proceed();
}
private void process(SimpleAnnotation simpleAnnotation) {
// advice logic
}
}
更新:修改了@kriegaex注释的代码
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。