【Spring源码】37. AOP准备工作之parse()详解(下篇)
上一篇文章我们详细介绍了parse()方法中的第一个步骤:注册自动代理模式创建器(【Spring源码】36. AOP准备工作之parse()详解(上篇)),这篇文章我们继续介绍parse()方法中的第二个步骤:解析子节点
解析<aop:config>
下的子节点
继续解析<aop:config>
子节点下的
-
<aop:pointcut>
-
<aop:advice>
-
<aop:aspect>
在这里会根据获取到的localName
进入不同的if条件语句,进而执行不同的解析方法
-
parsePointcut()
-
parseAdvisor()
-
parseAspect()
下面我们按照我们的测试代码中的XML配置(如下图)捋一遍流程(。・ω・。)ノ
由于获取到的localName
为"aspect",满足ASPECT.equals(localName)
为true
的条件,所以进入parseAspect()
方法中
parseAspect()
先获取<aop:aspect>
的两个属性:
id
属性
ref
属性(代表切面,必须配置)
接着解析<aop:aspect>
下的declare-parents
节点,通过DeclareParentsAdvisor
作为beanClass
加载,然后继续解析其他节点
在获取到节点后,遍历循环,解析其下的Advice
类型的节点,通过调用isAdviceNode()
判断遍历到的当前节点是否为Advice
类型的节点
isAdviceNode()
判断是否为Advice
节点
如上图中方法上面的注释,Advice
类型的节点有5个:
-
{ @code before}
-
{ @code after}
-
{ @code after-returning}
-
{ @code after-throwing}
-
{ @code around}
与上面任何一个类型形同返回值即为true
解析成功则继续向下执行
parseAdvisor()
方法parseAdvisor()
先生成了methodDefinition
(解析advice
中的"method"属性,并包装为MethodLocatingFactoryBean
对象 )、aspectFactoryDef
(关联aspectName
,包装为SimpleBeanFactoryAwareAspectInstanceFactory
对象)这两个RootBeanDefinition
对象,并依次为他俩赋值
随后解析pointcut属性,将上面👆两个对象传入了方法createAdviceDefinition()
中,包装为AspectJMethodBeforeAdvice
对象返回并赋值给名为adviceDef
的AbstractBeanDefinition
对象
最后将这个对象包装为名为advisorDefinition
的RootBeanDefinition
对象并为相关的属性赋值
最后完成注册,就可以在parseContext
对象的readerContext -> reader -> registry -> beanDefinitionMap
属性中看到这个AspectJPointcutAdvisor
对象叻(AspectJPointcutAdvisor#0
)
那么问题来了:这些生成的RootBeanDefinition
对象有什么区别吗,他们具体都是哪些类呢?
我们先来详细介绍下createAdviceDefinition()
这个方法
createAdviceDefinition()
进入方法createAdviceDefinition()
首先根据adviceElement
节点通过调用getAdviceClass()
方法分析出是什么类型的Advice
,获取到一个adviceDefinition
对象
getAdviceClass()
这个方法其实与刚刚介绍过的isAdviceNode()
判断的类型是完全一致的
继续给刚刚获取到的adviceDefinition
对象设置属性值
- 设置
aspectName
属性和declarationOrder
属性
- 设置
returning
、throwing
、arg-name
这3个属性(先判断,有则设置)
- 设置构造函数的入参变量
- Method
- AspectJExpressionPointcut
- AspectInstanceFactory
然后解析<point-cut>
节点
parsePointcutProperty()
至此,方法createAdviceDefinition()
执行结束,返回一个AbstractBeanDefinition
类型的对象adviceDef
。我们也来回答下介绍方法前的问题:这些生成的RootBeanDefinition
对象具体都是哪些类呢?
methodDefinition
:MethodLocatingFactoryBean
aspectFactoryDef
:SimpleBeanFactoryAwareAspectInstanceFactory
adviceDef
:AspectJMethodBeforeAdvice
adviceDefinition
:AspectJPointcutAdvisor
回到方法parseAspect()
中,将当前解析过的beanDefinition
(advisorDefinition
)添加进集合beanDefinitions
中
接着进入下一轮循环♻️,继续解析列表中的节点
第二次循环执行完成在parseContext
对象的readerContext -> reader -> registry -> beanDefinitionMap
属性中又多了一个AspectJPointcutAdvisor
对象(AspectJPointcutAdvisor#1
),嘿嘿没错每完成一次循环就会多一个~~0、1、2……递增
循环结束后,返回到parse()方法中,由于我在XML配置文件(如下图)中加了两个aspect
标签🏷️,所以childElts
里有两个Element
,于是会再按上面👆得大致流程再执行一遍
全部遍历完成后一路返回
完成撒个花(。・ω・。)ノ🎉
转载自:https://juejin.cn/post/7176434721826537530