前言
之前的文章解析了spring中 ioc的核心流程 ,以及包括了bean定义的解析和加载 到容器中,以及 整个spring框架ioc基本流程,以及bean的生命周期 包括 单例bean 以及非懒加载bean实例的创建过程,getbean dogetbean createbean docreatebean 等流程 下去 spring 对di属性 以及 构造器注入 使用三级缓存来解决 循环依赖的问题等等。本篇文章会继续下去,解析 aop源码 ,都知道 spring 对创建实例过后 会有对bean的增强 以及初始化方法的调用。而aop则是基于bean的生命周期上的功能增强。
AOP的基本概念
Aspect、Join point、 Advice、Pointcut、Introduction、Target object、AOP proxy、Weaving
Spring包含的五种通知
AOP代理方式
AOP 默认为 AOP 代理使用标准 JDK 动态代理。这使得任何接口(或一组接口)都可以被代理。 Spring AOP 也可以使用 CGLIB 代理。这是代理类而不是接口所必需的。默认情况下,如果业务对象未实现接口,则使用 CGLIB。由于对接口而不是类进行编程是一种很好的做法,因此业务类通常实现一个或多个业务接口。在那些(希望很少见)需要建议未在接口上声明的方法或需要将代理对象作为具体类型传递给方法的情况下,可以强制使用 CGLIB。 重要的是要掌握 Spring AOP 是基于代理的这一事实。请参阅了解 AOP 代理,以全面了解此实现细节的实际含义。
Spring中AOP的用法
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.9.6</version>
</dependency>
![](https://img-blog.csdnimg.cn/492a7b7d655e4795a49328e221ff413b.png?x-oss-process=image/watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBA6Lip6Lip6Lip5LuO6Lip,size_20,color_FFFFFF,t_70,g_se,x_16)
![](https://img-blog.csdnimg.cn/3b9f5cf7a3064e3285a749a3eb8ba513.png?x-oss-process=image/watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBA6Lip6Lip6Lip5LuO6Lip,size_20,color_FFFFFF,t_70,g_se,x_16)
<!--将advice做为bean放入容器-->
<bean id="myBeforeAdvice" class="edu.dongnao.courseware.spring.aop.MyBeforeAdvice" />
<bean id="yyArroundAdvice" class="edu.dongnao.courseware.spring.aop.MyArroundAdvice" />
<!--第一种方式:advisor 配置切点和通知,aop下以do开头的方法-->
<!--
expose-proxy="false" 是否暴露当前代理对象为ThreadLocal模式
proxy-target-class="false" 是否使用代理类的形式
-->
<aop:config>
<aop:pointcut id="doMethods" expression="execution(* edu.dongnao.courseware.spring.aop.*.do*(..))" />
<aop:advisor advice-ref="myBeforeAdvice" pointcut-ref="doMethods" />
<aop:advisor advice-ref="yyArroundAdvice"
pointcut="execution(* edu.dongnao.courseware.spring.aop.*.service*(..))"/>
</aop:config >
Aspect注解方式
<!--第二种方式:aspect-->
<!--proxy-target-class表示使用CGLIB方式处理代理类-->
<!--aop下以service开头的方法-->
<aop:config>
<aop:pointcut id="services" expression="execution(* edu.dongnao.courseware.spring.aop.*.service*(..))" />
<aop:aspect id="a1" ref="aspectAdviceBean" order="1">
<aop:before method="before1" pointcut-ref="doMethods" />
<aop:before method="before2" pointcut-ref="doMethods"/>
<!--
and args(tk,..),还需要匹配参数,第一个参数类型必须与Advice中tk一致
arg-name
-->
<aop:before method="before3" pointcut="execution(* edu.dongnao.courseware.spring.aop.*.do*(..)) and args(tk,..)"/>
<aop:before method="before4" pointcut="execution(* edu.dongnao.courseware.spring.aop.*.do*(..)) and args(tk,ti)"/>
<aop:around method="arround1" pointcut-ref="services"/>
<aop:around method="arround2" pointcut="execution(* edu.dongnao.courseware.spring.aop.*.service*(..)) and args(name)"/>
<aop:after-returning method="afterReturning" pointcut-ref="services" returning="retValue"/>
<aop:after-throwing method="afterThrowing" pointcut-ref="services" throwing="e"/>
<aop:after method="after" pointcut-ref="services"/>
</aop:aspect>
</aop:config>
@Aspect注解配置方式
@Configuration
@EnableAspectJAutoProxy
public class AppConfig {
}
![](https://img-blog.csdnimg.cn/9fc49f4e85c140fb8c1a7b7045fe2074.png?x-oss-process=image/watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBA6Lip6Lip6Lip5LuO6Lip,size_20,color_FFFFFF,t_70,g_se,x_16)
![](https://img-blog.csdnimg.cn/4873e9e9cb7a41dfb1089b22681de16f.png?x-oss-process=image/watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBA6Lip6Lip6Lip5LuO6Lip,size_20,color_FFFFFF,t_70,g_se,x_16)
PointCut接口体系
methodmatcher 方法匹配器, 以及类匹配器。
定义的字符串 对应的注解方式。
Advisor接口体系
匹配的advisor 接口 顶层的一个接口,
继承体系下面包含了名称匹配 正则表达式的,
获取切点 等。
getthis 获取代理对象,以及 目标对象。
这里面包括了通用 环绕 中使用等等。
Spring AOP源码解析
怎么查看 aop的入口 ,可以通过 EnableAspectJAutoProxy 注解 也可以通过 aop的命名空间进去看 spring.handler
配置的解析过程
<aop:config >
<aop:pointcut id="doMethods" expression="execution(*
edu.dongnao.courseware.spring.aop.*.do*(..))" />
<aop:advisor advice-ref="myBeforeAdvice" pointcut-ref="doMethods" />
<aop:advisor advice-ref="yyArroundAdvice" pointcut="execution(*
edu.dongnao.courseware.spring.aop.*.service*(..))"/>
</aop:config >
<aop:aspectj-autoproxy />
config的解析
对应的属性 等等。
对应的子标签解析 并注册utils 将 aspectj 注册进去 并成为 bean定义。
@Nullable
public static BeanDefinition registerAspectJAutoProxyCreatorIfNecessary(
BeanDefinitionRegistry registry, @Nullable Object source) {
return registerOrEscalateApcAsRequired(AspectJAwareAdvisorAutoProxyCreator.class,
registry, source);
}
![](https://img-blog.csdnimg.cn/1337b0b838cf4270a137260da4003767.png?x-oss-process=image/watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBA6Lip6Lip6Lip5LuO6Lip,size_13,color_FFFFFF,t_70,g_se,x_16)
![](https://img-blog.csdnimg.cn/d2741638a11e4152a380b55180742b86.png?x-oss-process=image/watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBA6Lip6Lip6Lip5LuO6Lip,size_20,color_FFFFFF,t_70,g_se,x_16)
当在xml中配置了<aop:aspectj-autoproxy>,则会选AnnotationAwareAspectJAutoProxyCreator。
会给我们创建自定义。
默认就创建的 aspectj的形式。
创建的advisor
解析的aspectj
这里比较麻烦一点,应对不同 标签添加不同的 class类型 进行初始化。
![](https://img-blog.csdnimg.cn/873e1e11b6874a83a43511217c0df829.png?x-oss-process=image/watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBA6Lip6Lip6Lip5LuO6Lip,size_20,color_FFFFFF,t_70,g_se,x_16)
AbstractAutoProxyCreator实现类
就是我们前面看到的三个不同优先等级的AutoProxyCreator。
AspectJ自动代理构建器 属性的处理
AopConfigUtils.forceAutoProxyCreatorToUseClassProxying
注解中代理类 的方式。
自动代理的创建者。
aop中代理处理的方法 都是在beanpostprocess中做的功能增强。
判断代理生成的地方去处理。
织入过程
如何判断Bean要不要被创建代理
如何排除advice Bean的代理创建?
wrapIfNecessary、postProcessBeforeInstantiation两个方法都有类似的判断
if (isInfrastructureClass(beanClass) || shouldSkip(beanClass, beanName)) {
this.advisedBeans.put(cacheKey, Boolean.FALSE); return null;
}
![](https://img-blog.csdnimg.cn/9c79db2aa01549c19ebcf0640c814b70.png?x-oss-process=image/watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBA6Lip6Lip6Lip5LuO6Lip,size_20,color_FFFFFF,t_70,g_se,x_16)
AspectJAwareAdvisorAutoProxyCreator#shouldSkip方法中判断。
![](https://img-blog.csdnimg.cn/09c6d4cf786e438d97629f4adaec75e6.png?x-oss-process=image/watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBA6Lip6Lip6Lip5LuO6Lip,size_20,color_FFFFFF,t_70,g_se,x_16)
方法被调用的增强过程
在AbstractAdvisorAutoProxyCreator#findEligibleAdvisors方法中
![](https://img-blog.csdnimg.cn/4e2b9fd5127f4a1da20049fb701b4359.png?x-oss-process=image/watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBA6Lip6Lip6Lip5LuO6Lip,size_20,color_FFFFFF,t_70,g_se,x_16)
![](https://img-blog.csdnimg.cn/09c65301dbb94ba3823cba80346bd58e.png?x-oss-process=image/watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBA6Lip6Lip6Lip5LuO6Lip,size_19,color_FFFFFF,t_70,g_se,x_16)
![](https://img-blog.csdnimg.cn/56f13b63e01e4fe687a5b7b2aa5822d3.png?x-oss-process=image/watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBA6Lip6Lip6Lip5LuO6Lip,size_19,color_FFFFFF,t_70,g_se,x_16)
![](https://img-blog.csdnimg.cn/b2d77189cd924d83ad07f64e118f9c36.png?x-oss-process=image/watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBA6Lip6Lip6Lip5LuO6Lip,size_19,color_FFFFFF,t_70,g_se,x_16)
判断是否需要创建aop代理对象。
匹配到通知 就创建代理。
都需要做区别开spring中的 ware接口代理的。
如何组织多个advice执行的?
都是对class进行匹配。
CglibMethodInvocation继承自ReflectiveMethodInvocation,proceed方法不变。