【Spring源码系列- IOC】
在文章【分析向】没有三级缓存会导致什么? 中,提到过一个方法——wrapIfNecessary(),就是在这个方法中为Bean创建的代理对象,介于篇幅原因,当时并咩有详细🔎分析这个方法,这篇文章我们进去wrapIfNecessary()这个方法中瞅瞅(。・ω・。)ノ
wrapIfNecessary()
wrapIfNecessary()方法一开始会依次进行一系列的判断,如果满足了任意的一个,就会直接返回传入的bean对象,都不满足才会开始代理对象的创建
一开始会先判断当前传入的bean对象是否已经处理过(从集合targetSourcedBeans中查询,能查询到说明当前bean已经被处理过了),如果处理过了,就直接返回
对于已经创建过代理对象也会直接返回(从集合advisedBeans中查询📖,如果查得到,就说明缓存中存在当前bean的代理对象,即当前bean已经创建过代理对象了)
接下来的两个方法也是继续判断是否需要创建代理的
isInfrastructureClass()
用于判断当前bean是否是Spring自带的bean(自带的bean无需进行代理)
这里对4个类进行了判断:
-
Advice.class
-
Pointcut.class
-
Advisor.class
-
AopInfrastructureBean.class
isAssignableFrom()
通过调用上面4个类的isAssignableFrom()方法来判断传入对象所代表的类或者接口是否与他们相同,或者是其超类或者超接口,如果是的话返回true,否则返回false
shouldSkip()
判断当前bean是否需要被略过
以上两个条件,满足任意一个,则将当前bean进行缓存,并返回
当前(。・ω・。)ノ
如果上面👆的条件都不满足,则要开始为当前bean创建代理对象了
getAdvicesAndAdvisorsForBean()
先通过调用getAdvicesAndAdvisorsForBean()方法获取当前bean的Advices和Advisors
findEligibleAdvisors()
在findEligibleAdvisors()方法中,从候选的通知器中找到合适正在创建的实例对象的通知器获取到的Advisors(获取当前系统中所有切面类的切面逻辑,封装成一个List对象)进行判断,看其切面定义是否能应用到当前Bean,在进行相关的拓展、排序操作,最终得到最终需要应用的Adviser
findCandidateAdvisors()
将当前系统中的切面类的切面逻辑进行封装,从而得到目标Advisors
进入其实现类
findAdvisorsThatCanApply()
对获取到的所有Advisor进行判断,看其切面定义是否可以应用到当前bean,从而得到最终需要应用的Advisors
通过同名方法findAdvisorsThatCanApply()从候选的通知器中找到合适正在创建的实例对象
在findAdvisorsThatCanApply()的一开始定义一个合适的增强器集合对象eligibleAdvisors,接着循环我们候选的增强器对象,判断我们的增强器对象是不是实现了IntroductionAdvisor(是否有引介增强),最后调用canApply()方法判断增强器是否适用于当前类型
canApply()
这里对Advisor的类型进行了判断(见末尾补充内容)
-
如果是IntroductionAdvisor的话,则调用IntroductionAdvisor类型的实例进行类的过滤
-
如果是PointcutAdvisor类型(我们用到的一般都是这个类型),转为PointcutAdvisor类型
再次进入同名方法,方法中先进行classFilter的natches方法校验,类型不匹配直接返回false
进行切点表达式的匹配判断最重要的就是ClassFilter和MethodMatcher这两个方法的实现。
在当前方法中,只有在类型匹配得上以后,才会再进行MethodMatcher方法级别的校验
这里顺便介绍下MethodMatcher中有两个matches方法:
-
参数:Method、targetClass
-
参数:Method、targetClass、Method的方法参数
他们两个的区别是:两个参数的matches是用于静态的方法,匹配三个参数的matches是在运行期动态的进行方法匹配的。
判断匹配器是不是IntroductionAwareMethodMatcher,创建一个集合用于保存targetClass的class对象,接着判断当前class是不是代理的class对象,如果不是就加入到集合中去;接着获取到targetclass所实现的接口的class对象并加入到集合中
接下来就是循环所有的class对象,通过class获取到所有的方法,循坏遍历获取到的方法,只要有一个方法能配到就会返回true
回到方法wrapIfNecessary()中,获取了当前bean的Advices和Advisors后,判断下获取到的集合advisors是否为🈳(🈳就是没找到),是就返回DO_NOT_PROXY,不为空则返回集合advisor s的数组对象
只要getAdvicesAndAdvisorsForBean()方法的返回值不是DO_NOT_PROXY,就会进入if条件语句的逻辑块,缓存当前bean的代理状态,然后调用createProxy()实现代理对象的创建,创建完成后,缓存生成的代理对象,随后一路返回,就获取到了的一个当前bean的代理对象
无论当前对象是否需要创建代理对象,都会先创建它的普通实例对象,只不过在后续的流程中会把这个普通的实例对象进行替换
ps:其实DO_NOT_PROXY的值就是null ⁄(⁄ ⁄ ⁄ω⁄ ⁄ ⁄)⁄
extendAdvisors()
提供hook方法,用于对目标Advisor进行扩展
sortAdvisors()
最后对需要代理的Advisors们按照一定的顺序进行排序
结束后将排好序的Advisors们返回
回到getAdvicesAndAdvisorsForBean()中,判断排好序的Advisors集合是否为空,空则返回“DO_NOT_PROXY”
如果排好序的Advisors的集合不等于“DO_NOT_PROXY”(不为空),就会开始为当前对象创建代理
createProxy()
createProxy()方法会创建代理对象并将该代理对象缓存并返回
首先,给bean定义设置暴露属性
exposeTargetClass()
主要功能就是设置ORIGINAL_TARGET_CLASS_ATTRIBUTEH的属性值
接着创建代理工厂、获取单当前类中相关属性,决定对于给定的bean是否应该使用targetClass而不是他的接口代理,检查proxyTargetClass设置以及preserverTargetClass属性
shouldProxyTargetClass()
如果proxyFactory.isProxyTargetClass()的值为false则会调用方法shouldProxyTargetClass()继续判断是使用JDK动态代理,还是CGLIB动态代理
再次进入同名方法
ORIGINAL_TARGET_CLASS_ATTRIBUTE这个变量表示的是Bean的定义属性,它可以表明一个给定的Bean是否应该被其目标类代理(在它首先被代理的情况下)。其值是TRUE或FALSE。如果代理工厂为一个特定的Bean建立了一个目标类代理,并希望强制Bean总是可以被投递到它的目标类(即使AOP建议通过自动代理被应用),那么代理工厂可以设置这个属性
evaluateProxyInterfaces()
evaluateProxyInterfaces()方法用于添加代理接口
一开始会初始化参数hasReasonableProxyInterface为false,然后判断目标类有没有实现的接口,如果有接口并且以下条件同时为true,则使用JDK动态代理,并将参数hasReasonableProxyInterface设为true
-
!isConfigurationCallbackInterface(ifc)
-
!isInternalLanguageInterface(ifc)
-
ifc.getMethods().length > 0
接下来如果确定使用JDK动态代理就会把所有目标类实现的接口都添加进代理工厂,如果不是就会把代理工厂的·屏proxyTargetClass属性设为true
添加完代理接口后,会开始构建增强器,设置要代理的目标类,随后进行代理的定制化(目前默认为空,就是啥都没干)
通过设置frozen属性控制代理工厂被配置后,是否还允许修改通知,默认值是false,最后调用getProxy()真正开始构建代理对象
getProxy()
此处会根据工厂的设置,创建一个可以反复调用的新的代理对象
createAopProxy()
创建代理工厂
添加或删除了接口,效果会有所不同。可以添加和删除拦截器。使用给定的类加载器(如果对代理的创建有必要)。
监听调用AdvisedSupportListener实现类的activated()方法
通过AopProxyFactory获取到AopProxy,这个AopProxyFactory是在初始化函数中定义的(DefaultAopProxyFactory)
再次进入同名方法中
这里首先选择使用哪种方式创建代理对象,如果满足以下3个条件中的任意一个,就会进入if条件代码块(不进入则使用JDK的提供的代理方式生成代理对象)
-
config.isOptimize() 是否对代理类的生成使用策略优化(默认为false)
-
config.isProxyTargetClass() 是否使用Cglib的方式创建代理对象(默认为false)
-
hasNoUserSuppliedProxyInterfaces(config) 目标类是否有接口存在且只有一个接口的时候接口类型不是SpringProxy类型(如下图)
接着从AdvisedSupport中获取目标类类对象,对目标类进行判断如果目标类是是接口或者Proxy类型的类则使用JDK的方式生成代理对象,否则使用CGLIB 进行动态代理
getProxy()
这个方法有两个实现
CglibAopProxy
我们先来看看CglibAopProxy的实现
从advised中获取ioc容器中配置的target对象,如果对象已经是CGLIB生成的,就取目标对象的父类作为目标对象的类,然后获取无法被代理的方法名(CGLIB的实现方式是继承,所以final、static修饰的方法不能被增强)
创建、配置增强器,配置其他信息(超类、代理类实现的接口、回调方法等)
这里有必要插播介绍下advisor、advice、adviced各自的含义
-
advisor 通知器包含advice和pointcut
-
advice 具体的某一个消息通知
-
adviced 用来配置代理(proxyFactory)
这部分代码中有个方法需要注意下AopProxyUtils中的completeProxiedInterfaces(this.advised)
此处的this.advised表示的是具体的代理工厂类也就是proxyFactory
completeProxiedInterfaces()
再次进入当前方法内的同名方法
根据AdvisedSupport类型中目标类的接口,如果目标类没有实现接口,就尝试获取目标类,如果目标类是接口,则添加到AdvisedSupport的接口中,如果是Proxy类型,也会尝试获取接口
最后将获取到的接口返回,回到方法getProxy()中,配置完属性后,回获取回调函数
getCallbacks()
首先对expose-proxy、isFrozen、isStatic这几个属性进行处理,接着将拦截器封装在DynamicAdvisedInterceptor中
new一个Callback类型的数组,将拦截器(回调函数)添加进数组,返回并赋值给变量callbacks
最后调用方法createProxyClassAndInstance() 通过Enhancer生成代理对象并设置返回
进入createClass()方法
详细看下createHelper()
preValidate()是校验callbackTypes、filter是否为空,以及为空时的处理
接着是一行特别长的代码,截图没截全,下面👇贴下代码
Object key = KEY_FACTORY.newInstance(
this.superclass != null ? this.superclass.getName() : null,
ReflectUtils.getNames(this.interfaces),
this.filter == ALL_ZERO ? null : new WeakCacheKey(this.filter),
this.callbackTypes,
this.useFactory,
this.interceptDuringConstruction,
this.serialVersionUID);
这段代码是通过newInstance()方法来为创建的EnhancerKey对象的属性赋值
接着设置当前enhancer的代理类的key标识,然后调用父类即AbstractClassGenerator的创建代理类,生成代理对象后返回
啊啊啊~这篇长湿俺叻、搞定( ̄∇ ̄)/
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/135369.html