【Bug记录】调用Controller中的方法的Service为null

原文链接:【Bug 记录】调用 Controller 中的方法的 Service 为 null

问题

今天写代码的时候遇到了一个奇怪的Bug,在Controller中调用某个方法时突然报空指针异常,打断点时发现service为null,并尝试了数种注入方式,发现均为null。

原因分析

首先去检查了一下Service上的注解,发现是有 @Service 注解的,因为使用了Lombok的 @RequiredArgsConstructor 注解1,所以在想是不是Lombok的原因,后面去掉该注解,分别尝试了使用 @Autowired 注入、@Resource 注入以及构造器注入,调用时发现仍为null。

上网查询资料后发现关注点错了,既然Service添加了对应注解,且也尝试了不同的注入方法,如果其他方法也均是使用这种方式注入且没出问题的,那就说明问题出在方法上。

在检查方法时发现,在Controller层,方法定义时使用了private 修饰,而不是正常的 public,如下:

查阅资料后发现:容器在扫描Bean并生成代理类的时候,只会生成被 publicprotected 修饰的方法的代理类,被 private 修饰的方法并不会生成代理类。

Q:

<think>好的,我现在需要解决用户的问题:在使用AOP切面拦截所有Controller请求时,如何将Controller方法上的自定义注解携带到切面方法中去。让我仔细分析一下这个问题。 首先,用户已经定义了一个切面来记录日志,拦截所有的Controller请求。这些Controller中的某些方法可能带有自定义注解,用来标识请求类型。用户希望在切面处理时能够获取到这些自定义注解的信息。 那么,我需要回忆一下Spring AOP的相关知识,尤其是如何获取方法上的注解。通常,在切面中可以通过连接点(JoinPoint)来获取被拦截的方法的信息。具体来说,ProceedingJoinPoint提供了访问目标方法细节的能力。 接下来,我需要考虑如何从连接点中提取方法上的注解。Spring AOP的JoinPoint接口有一个getSignature方法,返回MethodSignature,进而可以获取到目标方法。一旦获取到方法对象,就可以使用getAnnotation()方法来查找特定的注解。 不过,用户提到可能有不同的自定义注解,所以可能需要动态地获取方法上的所有注解,或者根据特定类型获取。这里的关键是确定用户是否需要获取特定类型的注解,还是需要获取所有存在的自定义注解。 另外,还要考虑到注解是否可以继承,或者是否需要在运行时保留。自定义注解必须使用@Retention(RetentionPolicy.RUNTIME)才能在运行时通过反射获取到,否则无法在切面中访问。 可能的解决步骤: 1. 在切面方法中,通过ProceedingJoinPoint获取目标方法。 2. 遍历方法的注解,找到需要的自定义注解。 3. 将注解的信息提取出来,传递给切面中的处理逻辑。 需要注意的是,如果用户的自定义注解可能有多个,或者需要处理不同种类的注解,代码可能需要更灵活的处理方式,比如检查注解的类型并做相应的处理。 另外,还要考虑是否有可能在类级别上也有注解,此时可能需要同时检查类和方法上的注解。不过用户的问题明确提到是Controller方法上的注解,所以可能只需要处理方法级别的。 可能的代码示例: 在切面的通知方法中,例如@Around通知,可以这样写: MethodSignature signature = (MethodSignature) joinPoint.getSignature(); Method method = signature.getMethod(); MyCustomAnnotation annotation = method.getAnnotation(MyCustomAnnotation.class); 如果用户需要获取所有自定义注解,可能需要遍历method.getAnnotations(),然后根据注解的类型进行判断。 不过,用户的问题中提到“携带这些注解到具体的方法里面去”,可能是指将注解的信息作为参数传递给切面中的其他方法,或者在日志记录中使用这些注解的属性。这时候,只需要在切面中获取到注解对象,然后提取所需的属性即可。 例如,假设自定义注解是@LogType("type1"),那么在切面中可以获取到该注解,并获取其value值,然后记录到日志中。 总结步骤: 1. 获取目标方法。 2. 从方法上获取自定义注解。 3. 提取注解中的信息,用于日志记录。 另外,需要注意如果注解是添加在接口方法上而不是实现类方法上,可能需要使用AnnotationUtils.findAnnotation()方法来查找,因为getAnnotation()可能无法获取到接口上的注解。Spring的AnnotationUtils可以帮助更全面地查找注解,包括继承和接口的情况。 因此,更健壮的代码可能使用Spring的工具类来获取注解,确保即使注解在接口或父类上也能正确获取到。 最后,验证这个过程是否存在可能的错误,比如方法不存在注解时的空指针处理,或者如何支持多个不同的自定义注解。可能需要用户明确他们需要处理的具体情况,但根据问题描述,目前的方案应该能满足基本需求。</think>在Spring AOP中获取Controller方法上的自定义注解,可以通过以下步骤实现: --- ### **步骤说明** #### **1. 定义自定义注解** 确保注解保留策略为`RUNTIME`,例如: ```java @Target(ElementType.METHOD) @Retention(RetentionPolicy.RUNTIME) public @interface RequestType { String value() default ""; } ``` --- #### **2. 在切面中获取注解** 通过`ProceedingJoinPoint`获取方法签名,再提取注解: ```java @Aspect @Component public class LogAspect { @Around("execution(* com.example.controller.*.*(..))") public Object logAround(ProceedingJoinPoint joinPoint) throws Throwable { // 获取方法签名 MethodSignature signature = (MethodSignature) joinPoint.getSignature(); Method method = signature.getMethod(); // 获取方法上的注解 RequestType requestTypeAnnotation = method.getAnnotation(RequestType.class); // 使用注解信息 if (requestTypeAnnotation != null) { String type = requestTypeAnnotation.value(); System.out.println("请求类型:" + type); } return joinPoint.proceed(); } } ``` --- #### **3. 处理继承/接口的注解(可选)** 如果注解可能定义在接口或父类方法中,使用Spring工具类`AnnotationUtils`: ```java RequestType annotation = AnnotationUtils.findAnnotation(method, RequestType.class); ``` --- ### **关键点解析** 1. **获取方法对象** 通过`joinPoint.getSignature()`转型为`MethodSignature`,再调用`getMethod()`获取目标方法。 2. **提取注解** 直接通过`method.getAnnotation()`或`AnnotationUtils.findAnnotation()`获取注解实例。 3. **注解属性使用** 直接调用注解的属性方法(如`value()`)获取配置值。 --- ### **完整示例代码** ```java // 自定义注解 @Target(ElementType.METHOD) @Retention(RetentionPolicy.RUNTIME) public @interface RequestType { String value(); } // Controller中使用注解 @RestController public class MyController { @RequestType("API_V1") @GetMapping("/test") public String test() { return "OK"; } } // 切面处理 @Aspect @Component public class LogAspect { @Around("execution(* com.example.controller..*.*(..))") public Object logRequest(ProceedingJoinPoint pjp) throws Throwable { Method method = ((MethodSignature) pjp.getSignature()).getMethod(); RequestType annotation = AnnotationUtils.findAnnotation(method, RequestType.class); if (annotation != null) { String logMessage = String.format("拦截到请求类型:%s", annotation.value()); System.out.println(logMessage); } return pjp.proceed(); } } ``` --- ### **注意事项** - **注解保留策略**:必须使用`@Retention(RetentionPolicy.RUNTIME)`,否则反射无法获取。 - **切入点表达式**:确保切面能正确拦截Controller方法(如`execution(* com.example.controller..*.*(..))`)。 - **空值处理**:如果方法可能没有注解,需添加`if (annotation != null)`判断避免NPE。 通过这种方式,您可以在切面中动态获取Controller方法上的自定义注解,并根据注解内容实现差异化日志记录
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Bummon.

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值