当前位置: 首页 > 知识库问答 >
问题:

Spring Boot中类级别和方法级别的注释方面(NullPointerException)

梁丘逸仙
2023-03-14
@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参数变为null,aspect方法抛出NullPointerException。

@Around(value = " @annotation(simpleAnnotation) || @within(simpleAnnotation)", argNames = "simpleAnnotation")
    @Around(value = "@within(simpleAnnotation) || @annotation(simpleAnnotation) || @within(simpleAnnotation)", argNames = "simpleAnnotation")

这似乎起作用了,但这是一个好的解决办法吗?

编辑:此解决方案也不起作用。如果我在类和方法级别上都有注释,假设类级别的注释值为false,而方法级别为true,那么注释值将为false。

共有1个答案

韦俊英
2023-03-14

要解决NPE,可以将切入点指示符(@inne@annotation)重构为同一方面中的两个不同的建议方法。

基于ISAlloved值处理的逻辑可以保存在一个公共方法中,并从两个advice方法调用。

举例说明:

@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, SimpleAnnotation simpleAnnotation)
            throws Throwable {
        System.out.println("Simple annotation value:" + simpleAnnotation.isAllowed() + " , ASPECT-LOG :"
                + proceedingJoinPoint.getSignature().getName());
        process(simpleAnnotation);
        return proceedingJoinPoint.proceed();
    }

    private void process(SimpleAnnotation simpleAnnotation) {
        // advice logic
    }
}
 类似资料:
  • Spring Transaction Propagation如何为Propagation_REQUIRED和Propagation_REQUIRED_NEW工作? 请提供有关类到类级别和方法到方法级别的传播的信息。 我还需要知道如何初始化/启动这些事务,并在当前事务完成时恢复以前的事务,以进行传播。 在需要传播和需要新传播的情况下使用单个事务时,事务将如何决定何时需要提交/回滚?

  • 我们在hello-world-test的基础上,我们新建了一个名为method-security的 Gradle 项目。 本项目用于演示方法级别的安全设置。 build.gradle 修改 build.gradle 文件,让我们的method-security项目成为一个新的项目。 修改内容也比较简单,修改项目名称及版本即可。 jar { baseName = 'method-securi

  • Dorado支持对方法级别的超时时间设置,默认使用统一的值 1. XML配置方式 <bean id="clientProxy" class="com.meituan.dorado.config.service.spring.ReferenceBean" destroy-method="destroy"> <property name="serviceInterface" value="com.

  • 问题内容: 我知道这是一个不好的做法,但是需要完成,否则我需要切换到。有没有一种类似于JUnit 3的testSuite的方法来指定要在类中运行的测试的顺序? 问题答案: 如果你确定你 真的 想这样做:有可能是一个更好的办法,但是这是我能拿出… JUnit4有一个注释:它使您可以覆盖测试的默认Runner。 在您的情况下,您将需要创建一个特殊的子类,并重写以按照您希望它们执行的顺序返回测试。例如,

  • 问题内容: Django 有两种方法,和。该文档说: 与gregation()不同,annotate()不是终端子句。annotate()子句的输出是QuerySet。 它们之间还有其他区别吗?如果没有,那为什么存在呢? 问题答案: 我将重点放在示例查询而不是文档中的引用上。A计算整个查询集的值。计算查询集中每个项目的汇总值。 聚合 返回包含查询集中所有书籍的平均价格的字典。 注解 q 是书籍的查

  • 我创建了一个包含一些基本crud方法的CrudController。这很好用。当我想保护这个控制器时,我可以重写超类中的方法,这很好。然而,我不想仅仅为了安全而重写每个方法。为此,我想在类上使用@Secured或@PreAuthorize。 我使用的是Spring Boot 2.2.2(最新版本)。 示例Crud基类 实现类 预期行为 当一个类被注释为@PreAuthorize或@安全时,我希望所