Spring源码分析:AOP源码解析(上篇)
2018-01-14 18:35
573 查看
前言
前面写了六篇文章详细地分析了Spring Bean加载流程,这部分完了之后就要进入一个比较困难的部分了,就是AOP的实现原理分析。为了探究AOP实现原理,首先定义几个类,一个Dao接口:
AOP实现原理——找到Spring处理AOP的源头
有很多朋友不愿意去看AOP源码的一个很大原因是因为找不到AOP源码实现的入口在哪里,这个确实是。不过我们可以看一下上面的测试代码,就普通Bean也好、AOP也好,最终都是通过getBean方法获取到Bean并调用方法的,getBean之后的对象已经前后都打印了TimeHandler类printTime()方法里面的内容,可以想见它们已经是被Spring容器处理过了。既然如此,那无非就两个地方处理:
加载Bean定义的时候应该有过特殊的处理
getBean的时候应该有过特殊的处理
因此,本文围绕【1.加载Bean定义的时候应该有过特殊的处理】展开,先找一下到底是哪里Spring对AOP做了特殊的处理。代码直接定位到DefaultBeanDefinitionDocumentReader的parseBeanDefinitions方法:
首先第2行从<aop:config>这个Node(参数Element是Node接口的子接口)中拿到Namespace=”http://www.springframework.org/schema/aop“,第3行的代码根据这个Namespace获取对应的NamespaceHandler即Namespace处理器,具体到aop这个Namespace的NamespaceHandler是org.springframework.aop.config.AopNamespaceHandler类,也就是第3行代码获取到的结果。具体到AopNamespaceHandler里面,有几个Parser,是用于具体标签转换的,分别为:
config–>ConfigBeanDefinitionParser
aspectj-autoproxy–>AspectJAutoProxyBeanDefinitionParser
scoped-proxy–>ScopedProxyBeanDefinitionDecorator
spring-configured–>SpringConfiguredBeanDefinitionParser
接着,就是第8行的代码,利用AopNamespaceHandler的parse方法,解析<aop:config>下的内容了。
AOP Bean定义加载——根据织入方式将<aop:before>、<aop:after>转换成名为adviceDef的RootBeanDefinition
上面经过分析,已经找到了Spring是通过AopNamespaceHandler处理的AOP,那么接着进入AopNamespaceHandler的parse方法源代码:向Spring容器注册了一个BeanName为org.springframework.aop.config.internalAutoProxyCreator的Bean定义,可以自定义也可以使用Spring提供的(根据优先级来)
Spring默认提供的是org.springframework.aop.aspectj.autoproxy.AspectJAwareAdvisorAutoProxyCreator,这个类是AOP的核心类,留在下篇讲解
在这个方法里面也会根据配置proxy-target-class和expose-proxy,设置是否使用CGLIB进行代理以及是否暴露最终的代理。
<aop:config>下的节点为<aop:aspect>,想见必然是执行第18行的代码parseAspect,跟进去:
接着,如果是上述五种标签之一,那么进入第33行~第34行的parseAdvice方法:
根据织入方式(before、after这些)创建RootBeanDefinition,名为adviceDef即advice定义
将上一步创建的RootBeanDefinition写入一个新的RootBeanDefinition,构造一个新的对象,名为advisorDefinition,即advisor定义
将advisorDefinition注册到DefaultListableBeanFactory中
下面来看做的第一件事createAdviceDefinition方法定义:
before对应AspectJMethodBeforeAdvice
After对应AspectJAfterAdvice
after-returning对应AspectJAfterReturningAdvice
after-throwing对应AspectJAfterThrowingAdvice
around对应AspectJAroundAdvice
createAdviceDefinition方法剩余逻辑没什么,就是判断一下标签里面的属性并设置一下相应的值而已,至此<aop:before>、<aop:after>两个标签对应的AbstractBeanDefinition就创建出来了。
AOP Bean定义加载——将名为adviceDef的RootBeanDefinition转换成名为advisorDefinition的RootBeanDefinition
下面我们看一下第二步的操作,将名为adviceDef的RootBeanD转换成名为advisorDefinition的RootBeanDefinition,跟一下上面一部分ConfigBeanDefinitionParser类parseAdvice方法的第26行~32行的代码:第4行~第7行的代码是用于判断<aop:aspect>标签中有没有”order”属性的,有就设置一下,”order”属性是用来控制切入方法优先级的。
AOP Bean定义加载——将BeanDefinition注册到DefaultListableBeanFactory中
最后一步就是将BeanDefinition注册到DefaultListableBeanFactory中了,代码就是前面ConfigBeanDefinitionParser的parseAdvice方法的最后一部分了:
第3行向DefaultListableBeanFactory中注册,BeanName已经有了,剩下的就是Bean定义,Bean定义的解析流程之前已经看过了,就不说了。
AOP Bean定义加载——AopNamespaceHandler处理<aop:pointcut>流程
回到ConfigBeanDefinitionParser的parseAspect方法:第5行~第7行的代码构建了一个Aspect标签组件定义,并将Apsect标签组件定义推到ParseContext即解析工具上下文中,这部分代码不是关键。
第9行的代码拿到所有<aop:aspect>下的pointcut标签,进行遍历,由parsePointcut方法进行处理:
第8行的代码推送一个PointcutEntry,表示当前Spring上下文正在解析Pointcut标签。
第9行的代码创建Pointcut的Bean定义,之后再看,先把其他方法都看一下。
第10行的代码不管它,最终从NullSourceExtractor的extractSource方法获取Source,就是个null。
第12行~第18行的代码用于注册获取到的Bean定义,默认pointcutBeanName为<aop:pointcut>标签中定义的id属性:
如果<aop:pointcut>标签中配置了id属性就执行的是第13行~第15行的代码,pointcutBeanName=id
如果<aop:pointcut>标签中没有配置id属性就执行的是第16行~第18行的代码,和Bean不配置id属性一样的规则,pointcutBeanName=org.springframework.aop.aspectj.AspectJExpressionPointcut#序号(从0开始累加)
第20行~第21行的代码向解析工具上下文中注册一个Pointcut组件定义
第23行~第25行的代码,finally块在<aop:pointcut>标签解析完毕后,让之前推送至栈顶的PointcutEntry出栈,表示此次<aop:pointcut>标签解析完毕。
最后回头来一下第9行代码createPointcutDefinition的实现,比较简单:
<aop:pointcut>标签对应解析出来的BeanDefinition是RootBeanDefinition,且RootBenaDefinitoin中的Class是org.springframework.aop.aspectj.AspectJExpressionPointcut
<aop:pointcut>标签对应的Bean是prototype即原型的
这样一个流程下来,就解析了<aop:pointcut>标签中的内容并将之转换为RootBeanDefintion存储在Spring容器中。
相关文章推荐
- 【Spring源码分析】AOP源码解析(上篇)
- 【Spring源码分析】AOP源码解析(上篇)
- Spring源码分析:AOP源码解析(上篇)
- Spring源码解析之四 ------ AOP原理和源码分析
- 【Spring源码分析】AOP源码解析(下篇)
- Spring源码分析:AOP源码解析(下篇)
- Spring源码分析:AOP源码解析(下篇)
- 【Spring源码分析】AOP源码解析(下篇)
- Spring源码解析-AOP简单分析
- Spring Aop源码分析
- Spring----AOP面向切面编程例子解析(附源码)
- Spring源码情操陶冶-AOP之Advice通知类解析与使用
- Spring对注解(Annotation)处理源码分析2——解析和注入注解配置的资源
- spring aop源码实现分析
- Spring基础系列-AOP源码分析
- Spring源码分析之ProxyFactoryBean方式实现Aop功能的分析
- Spring对注解(Annotation)处理源码分析2——解析和注入注解配置的资源
- spring源码分析AOP-02
- Spring对注解(Annotation)处理源码分析2——解析和注入注解配置的资源
- Spring对注解(Annotation)处理源码分析2——解析和注入注解配置的资源