目录
1、Spring Aop是什么及实现原理概述
简单来说spring aop就是面向切面编程,对切面执行前置、后置等回调逻辑,实现功能增强。Spring AOP的实现对于接口来说使用的JDK的动态代理来实现的,而对于类的代理使用CGLIB来实现。
2、情景再现
①、cglib动态代理
在我自己的项目中创建了一个类
然后是aspect对类方法拦截,如下:
config类配置开启aop,proxyTargetClass这里我没有配置,其实从spring5开始默认使用的是jdk的动态代理
接下来我们看在这种情景下,使用的是那种代理方式
debug断点显示使用的是cglib代理,而且此时不管我proxyTargetClass设置为true还是false,使用的都是cglib代理,其实结果不难想象使用的就应该是cglib代理,因为此时我只有一个测试类,对类进行代理。
再来看下面一种场景。
②、基于接口的代理实现
首先是接口和接口实现类
方法前置通知
首先看看proxyTargetClass默认这种情况下是使用的哪种代理实现
很容易看出,使用的是jdk的代理。
再看一下如果proxyTargetClass = true,再看一下结果。
很明显又重新使用的是cglib的代理。
小小的总结:如果对于给定的类进行代理,只会使用cglib进行代理,如果给定接口和实现类,则我们可以动态的配置proxyTargetClass来决定使用哪种代理。
3、源码分析
知其然也要知其所以然,接下来从源码层面进行挖掘是如何控制代理的动态选择的。
首先第一步可以确定容器在启动成功之后就已经给我们创建好了各种bean,如果我们debug住先不getBean然后会发现,在bean工厂的单例池singletonObjects
中可以看到完全创建好的bean
然后我们的目标就是找到在源码中到底在哪里决定使用cglib还是jdk,正如上面所说,spring把所有bean创建完成之后会放入单例池中singletonObjects中,那我们就从放入singletonObjects为突破口进行排查,全局搜索singletonObjects.put方法在哪里使用的
很明显,在第一个地方(箭头所指)就是我们想要的,我们点进去,先不管这个方法是干嘛的,打个断点先,然后重启项目,看调用栈。
然后将beanName跳到我们自己的bean,便于查看执行流程。
根据调用栈我们来到getSingleton方法的246行,发现这个方法最终返回的是singletonObject,猜想这个应该就是返回代理类的,那么生成代理类就一定在这个方法里面,在方法里搜索singletonObject果不其然发现了方法singletonFactory.getObject();如果debug查看的话其实确实就是这个方法生成的,所以我们家进入这个方法,来到doGetBean的createBean方法
继续往里走,来到AbstractAutowireCapableBeanFactory.createBean方法,这个方法其他都是一些准备工作,核心在下面
沿着doCreateBean继续往里调用,里面调用的这个方法返回的是exposeObject,经debug排查查看这个对象状态会发现是在以下这个调用被生成了代理
使用同样的方式,我们查看里面调用的这个方法的这个wrappedBean的状态,发现生成代理是后置处理器起的作用
继续往里走,发现是遍历所有的后置处理器,执行业务逻辑,我们用debug调试到aop的后置处理器AnnotationAwareAspectAutoProxyCreator
然后进入后置处理器的方法内发现代理的生成还是通过wrapIfNecessary这个方法返回的。
进入到wrapIfNecessary这个方法,很容易看到有个createProxy方法返回了proxy,进入到createProxy,这个方法里面主要完成了两件事情,准备代理工厂和返回代理Bean
进入到getProxy方法,发现里面有两个方法调用。
第二个getProxy点进去我们发现其实现类就是cglib和jdk的代理选择,所以第一个方法的目的一定是选择其实现类来决定是调用cglib还是jdk去生成代理。于是进入第一个方法里面。
很明显第二个箭头才是生成代理,进去看看
看到下面这些代码就豁然开朗了,这才是决定使用cglib还是jdk由于JdkDynamicAopProxy和ObjenesisCglibAopProxy都实现了AopProxy,所以刚才getProxy方法调用的时候使用哪种实现是在这里返回不同的实现类决定的。
返回实现类后就是各自底层的代理生成了。而且这里我们同样也看到了proxyTargetClass是怎么起作用的。
个人才疏学浅,信手涂鸦,spring框架更多模块解读相关源码持续更新中,感兴趣的朋友请移步至个人公众号,谢谢支持😜😜......
公众号:wenyixicodedog