为什么SpringBoot中使用Cglib代理private方法会失效

1. 背景介绍

大家在SpringBoot中使用Cglib动态代理的时候,发现使用private关键字修饰方法会导致代理失效,就像下面这样 网上很多文章的解决方法都是将private改为public就可以了,但很少有文章解释为什么

本文将通过分析SpringBoot中如何创建代理对象的,来解释说明private为什么不行

严格意义上来说private并不会导致代理失效,而只是影响了调用的对象而已

2. Cglib

Cglib是一个强大的、高性能的代码生成库,Cglib是利用ASM字节码处理框架会生成三个类

  • 代理类
  • 代理类对应的FastClass类
  • 被代理类对应的FastClass类

代理类:

  • 继承了被代理类的

  • 内部有一个静态代码块会利用反射将被代理类的所有方法对应的Method保存起来,并根据Method创建MethodProxy也保存起来

  • MethodProxy:主要是保存原始方法和代理方法的签名(Signature)

FastClass类在这里不重要,我们主要看在代理的情况下,Cglib是怎么执行方法的,比方说执行hello1()方法

  • 代理类中的hello1()方法实际上是被代理类重写了的

  • hello1()是先通过MethodInterceptor执行代理方法(CGLIB <math xmlns="http://www.w3.org/1998/Math/MathML"> h e l l o 1 hello1 </math>hello16)

  • 然后代理方法(CGLIB <math xmlns="http://www.w3.org/1998/Math/MathML"> h e l l o 1 hello1 </math>hello16)才通过super关键字调用被代理类的hello1()方法

3. SpringBoot中是如何创建代理对象的

Spring中有一个BeanPostProcessor类,这是一个钩子类,主要就负责在Bean的各个生命周期阶段执行回调方法

其中就有一个子类:AnnotationAwareAspectJAutoProxyCreator,这个类正是负责创建代理对象的

紧接着我们来看这个子类的结构图:

还是比较的复杂的,我们不管,我们就看BeanPostProcessorpostProcessAfterInitialization在子类中是如何实现的

这个方法其实很简单,就是看bean是否需要被代理,如果需要就将代理后的对象返回,换句话说注册到Spring容器中的是代理对象, 并且代理对象是没有经过依赖注入的

紧接着我们看在SpringMVC中当通过参数解析器解析出入参的时候,是怎么执行目标方法的

这里是通过getBean()获取的对象是什么,就是我们代理对象

前面已经介绍过这个是如何正确的执行目标方法的,就是将原方法进行重写,最终在MethodInterceptor中才会执行 CGLIB$hello1$6()方法,而CGLIB$hello1$6()方法才会通过super关键字调用父类,也就是进行过依赖注入的对象

可是如果我们的方法是用private修饰的呢,privatefinal修饰的关键字是不能被重写的,也就是在代理对象中不存在我刚才说的CGLIB$hello1$6()方法,那这个时候反射执行的方法是在哪里执行的呢,就是在当前对象也就是代理对象中执行的,代理对象又没有进行依赖注入,所以说使用@Resource或者@Autowired一定为空

但即使在这种情况下我们依旧可以换一种思路去调用被代理对象中的属性:

4. 总结

总结:

  • private关键字并不会导致动态代理失效
  • 只不过由于注册到容器中的是代理对象,而代理对象本身无法重写privatefinal修饰的方法,又由于Spring没有对代理对象中的属性进行依赖注入
  • 最终才导致执行方法的时候只能调用代理对象中的属性,而无法调用父类(被代理对象)的属性
相关推荐
一 乐26 分钟前
考研论坛平台|考研论坛小程序系统|基于java和微信小程序的考研论坛平台小程序设计与实现(源码+数据库+文档)
java·数据库·学习·考研·微信·小程序·源码
潘多编程2 小时前
Spring Boot微服务架构设计与实战
spring boot·后端·微服务
2402_857589362 小时前
新闻推荐系统:Spring Boot框架详解
java·spring boot·后端
原机小子2 小时前
Spring Boot框架下的新闻推荐技术
服务器·spring boot·php
2401_857622662 小时前
新闻推荐系统:Spring Boot的可扩展性
java·spring boot·后端
侠客行03173 小时前
xxl-job调度平台之任务触发
java·后端·源码
2402_857589363 小时前
Spring Boot新闻推荐系统设计与实现
java·spring boot·后端
CoderJia程序员甲4 小时前
重学SpringBoot3-集成Redis(四)之Redisson
java·spring boot·redis·缓存
sco52824 小时前
SpringBoot 集成 Ehcache 实现本地缓存
java·spring boot·后端
原机小子4 小时前
在线教育的未来:SpringBoot技术实现
java·spring boot·后端