使用@Validated注解导致Controller里注入的Service为空

2023年12月7日

今天在写接口参数校验时遇到一个问题,将注解@Validated写在Controller上时导致注入的Service为空
Controller代码

@Validated
@RestController
@RequestMapping("test")
public class TestController {

    @Autowired
    private TestService testService;

    @GetMapping("say_hello")
    private String sayHello(@Size(max = 10, message = "名称最大长度不超过10") String name) {
        return testService.sayHello(name);
    }
}

结果
在这里插入图片描述
调试
在这里插入图片描述
通过断点调试发现注入的TestService为空,导致了空指针异常
解决方法
最终排查了半天终于发现了问题所在,先直接放上解决方法,下面再分析具体原因

将方法的private改成public

问题成功解决

在这里插入图片描述
原因分析

容器扫描bean生成代理类的时候,public和protected方法可以被正常代理,而private方法的不会被代理,属性的注入也是在代理类中完成,所以public/protected方法获取的注入属性是完成注入的属性,private方法获取的是未完成注入时的属性,所以是null。
加了AOP以后会有影响,如果controller层方法需要调用注入的bean或者service层,那么只能使用public。

问:@Validated是如何实现的?

@Validated 是通过 AOP(面向切面编程)机制实现的。在 Spring 框架中,@Validated 注解用于在控制器方法处理用户请求时,对传递给这些方法的参数进行校验。这个校验过程是通过切面(Aspect)实现的,具体来说是通过 Spring 的 ValidationInterceptor 切面和对应的 ValidationAspect 实现。
当控制器方法被调用时,Spring 会自动将 @Validated 注解与对应的参数绑定在一起,然后调用 ValidationInterceptor 切面的 preHandle 方法。在 preHandle 方法中,ValidationInterceptor 会对参数进行校验,如果参数不符合校验规则,则会抛出异常,中断请求的处理。
通过 AOP 机制,@Validated 注解可以方便地对控制器方法的参数进行校验,而不需要在每个控制器方法中手动编写校验逻辑。这种校验方式可以提高代码的可读性和可维护性,同时也可以减少代码的重复性。

问:为什么private方法无法被动态代理?

动态代理是一种在运行时创建代理类和对象的机制,通常用于拦截对特定对象的方法调用。在Java中,动态代理主要通过java.lang.reflect.Proxy类和java.lang.reflect.InvocationHandler接口实现。
当谈到private方法时,重要的是理解访问控制和封装的概念。private方法是一个被声明为private的方法,只能在其所在类内部访问。这意味着任何外部类(包括代理)都无法直接访问private方法。
动态代理在创建代理对象时,是通过调用目标对象的公共方法来模拟目标对象的行为。由于private方法不能被外部访问,动态代理无法模拟private方法的行为。即使你尝试创建代理,也无法实现对private方法的调用。
此外,从设计角度考虑,private方法是设计为隐藏在类内部的实现细节。通过限制外部对private方法的访问,可以保护类的内部状态和实现,确保数据的完整性和安全性。因此,不允许外部代理对象访问private方法是符合封装原则的。
总结来说,private方法无法被动态代理模拟调用,因为它们是私有的并且只能在其所在类内部访问。这是由访问控制和封装原则决定的,以保护类的内部状态和实现细节。

总结
总结来说,@Validated是通过AOP机制实现对方法参数的校验,AOP机制实现的原理是通过动态代理实现的,而动态代理无法模拟private方法的行为,所以导致自动注入的类为空。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值