likes
comments
collection
share

【Spring源码】37. AOP准备工作之parse()详解(下篇)

作者站长头像
站长
· 阅读数 47

上一篇文章我们详细介绍了parse()方法中的第一个步骤:注册自动代理模式创建器(【Spring源码】36. AOP准备工作之parse()详解(上篇)),这篇文章我们继续介绍parse()方法中的第二个步骤:解析子节点

解析<aop:config>下的子节点

继续解析<aop:config>子节点下的

  • <aop:pointcut>

  • <aop:advice>

  • <aop:aspect>

【Spring源码】37. AOP准备工作之parse()详解(下篇)

在这里会根据获取到的localName进入不同的if条件语句,进而执行不同的解析方法

  • parsePointcut()

  • parseAdvisor()

  • parseAspect()

下面我们按照我们的测试代码中的XML配置(如下图)捋一遍流程(。・ω・。)ノ

【Spring源码】37. AOP准备工作之parse()详解(下篇)

由于获取到的localName为"aspect",满足ASPECT.equals(localName)true的条件,所以进入parseAspect()方法中

【Spring源码】37. AOP准备工作之parse()详解(下篇)

parseAspect()

【Spring源码】37. AOP准备工作之parse()详解(下篇)

先获取<aop:aspect>的两个属性:

  • id属性
  • ref属性(代表切面,必须配置)

【Spring源码】37. AOP准备工作之parse()详解(下篇)

接着解析<aop:aspect>下的declare-parents节点,通过DeclareParentsAdvisor作为beanClass加载,然后继续解析其他节点

【Spring源码】37. AOP准备工作之parse()详解(下篇)

在获取到节点后,遍历循环,解析其下的Advice类型的节点,通过调用isAdviceNode()判断遍历到的当前节点是否为Advice类型的节点

isAdviceNode()

判断是否为Advice节点

【Spring源码】37. AOP准备工作之parse()详解(下篇)

如上图中方法上面的注释,Advice类型的节点有5个:

  • { @code before}

  • { @code after}

  • { @code after-returning}

  • { @code after-throwing}

  • { @code around}

与上面任何一个类型形同返回值即为true

解析成功则继续向下执行

【Spring源码】37. AOP准备工作之parse()详解(下篇)

parseAdvisor()

【Spring源码】37. AOP准备工作之parse()详解(下篇)

方法parseAdvisor()先生成了methodDefinition(解析advice中的"method"属性,并包装为MethodLocatingFactoryBean对象 )、aspectFactoryDef(关联aspectName,包装为SimpleBeanFactoryAwareAspectInstanceFactory对象)这两个RootBeanDefinition对象,并依次为他俩赋值

【Spring源码】37. AOP准备工作之parse()详解(下篇)

随后解析pointcut属性,将上面👆两个对象传入了方法createAdviceDefinition()中,包装为AspectJMethodBeforeAdvice对象返回并赋值给名为adviceDefAbstractBeanDefinition对象

【Spring源码】37. AOP准备工作之parse()详解(下篇)

最后将这个对象包装为名为advisorDefinitionRootBeanDefinition对象并为相关的属性赋值

【Spring源码】37. AOP准备工作之parse()详解(下篇)

最后完成注册,就可以在parseContext对象的readerContext -> reader -> registry -> beanDefinitionMap属性中看到这个AspectJPointcutAdvisor对象叻(AspectJPointcutAdvisor#0

【Spring源码】37. AOP准备工作之parse()详解(下篇)

那么问题来了:这些生成的RootBeanDefinition对象有什么区别吗,他们具体都是哪些类呢?

我们先来详细介绍下createAdviceDefinition()这个方法

createAdviceDefinition()

进入方法createAdviceDefinition()

【Spring源码】37. AOP准备工作之parse()详解(下篇)

首先根据adviceElement节点通过调用getAdviceClass()方法分析出是什么类型的Advice,获取到一个adviceDefinition对象

getAdviceClass()

这个方法其实与刚刚介绍过的isAdviceNode()判断的类型是完全一致的

【Spring源码】37. AOP准备工作之parse()详解(下篇)

继续给刚刚获取到的adviceDefinition对象设置属性值

  • 设置aspectName属性和declarationOrder属性
  • 设置returningthrowingarg-name这3个属性(先判断,有则设置)
  • 设置构造函数的入参变量
    • Method
    • AspectJExpressionPointcut
    • AspectInstanceFactory

然后解析<point-cut>节点

【Spring源码】37. AOP准备工作之parse()详解(下篇)

parsePointcutProperty()

【Spring源码】37. AOP准备工作之parse()详解(下篇)

至此,方法createAdviceDefinition()执行结束,返回一个AbstractBeanDefinition类型的对象adviceDef。我们也来回答下介绍方法前的问题:这些生成的RootBeanDefinition对象具体都是哪些类呢?

【Spring源码】37. AOP准备工作之parse()详解(下篇)

  • methodDefinition:MethodLocatingFactoryBean
  • aspectFactoryDef:SimpleBeanFactoryAwareAspectInstanceFactory
  • adviceDef:AspectJMethodBeforeAdvice
  • adviceDefinition:AspectJPointcutAdvisor

回到方法parseAspect()中,将当前解析过的beanDefinitionadvisorDefinition)添加进集合beanDefinitions

【Spring源码】37. AOP准备工作之parse()详解(下篇)

接着进入下一轮循环♻️,继续解析列表中的节点

第二次循环执行完成在parseContext对象的readerContext -> reader -> registry -> beanDefinitionMap属性中又多了一个AspectJPointcutAdvisor对象(AspectJPointcutAdvisor#1),嘿嘿没错每完成一次循环就会多一个~~0、1、2……递增

【Spring源码】37. AOP准备工作之parse()详解(下篇)

循环结束后,返回到parse()方法中,由于我在XML配置文件(如下图)中加了两个aspect标签🏷️,所以childElts里有两个Element,于是会再按上面👆得大致流程再执行一遍

【Spring源码】37. AOP准备工作之parse()详解(下篇)

全部遍历完成后一路返回

完成撒个花(。・ω・。)ノ🎉

转载自:https://juejin.cn/post/7176434721826537530
评论
请登录