Spring中AOP源码

Posted 踩踩踩从踩

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Spring中AOP源码相关的知识,希望对你有一定的参考价值。

IOC容器核心流程_踩踩踩从踩的博客-CSDN博客

前言

之前的文章解析了spring中 ioc的核心流程  ,以及包括了bean定义的解析和加载 到容器中,以及 整个spring框架ioc基本流程,以及bean的生命周期  包括 单例bean  以及非懒加载bean实例的创建过程,getbean  dogetbean  createbean  docreatebean  等流程 下去  spring 对di属性 以及  构造器注入  使用三级缓存来解决 循环依赖的问题等等。本篇文章会继续下去,解析 aop源码  ,都知道 spring  对创建实例过后  会有对bean的增强  以及初始化方法的调用。而aop则是基于bean的生命周期上的功能增强。

Core Technologies (spring.io)

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 代理,以全面了解此实现细节的实际含义。

 SpringAOP的用法

pom.xml 中引入 aspectj 依赖
<dependency> 
    <groupId>org.aspectj</groupId> 
    <artifactId>aspectjweaver</artifactId> 
    <version>1.9.6</version> 
</dependency>
传统 Advisor 方式 编程提供 Advice ,实现对应的 Advice 接口 配置 Advisor advice + pointcut Xml 配置方式 注意点: <aop:config> 的属性了解 Advisor xml 标签配置

<!--将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 advice 是基于方法的。 配置 Bean 定义 配置 Aspect (引用包含 advice 方法的 bean ),在里面配置各种 Advice method + pointcut
<!--第二种方式: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注解配置方式

开启 @Aspectj 注解方式支持:
@Configuration
@EnableAspectJAutoProxy 
public class AppConfig  

 

Advice 接口体系

PointCut接口体系

methodmatcher  方法匹配器, 以及类匹配器。

 

 定义的字符串  对应的注解方式。

 Advisor接口体系

匹配的advisor  接口   顶层的一个接口,

 

 继承体系下面包含了名称匹配    正则表达式的,

 获取切点 等。

 

JoinPoint 接口体系 在匹配时,除了方法的匹配 并且参数也可以匹配

 

getthis 获取代理对象,以及 目标对象。 

这里面包括了通用 环绕 中使用等等。

Spring AOP源码解析

 

 怎么查看  aop的入口 ,可以通过 EnableAspectJAutoProxy 注解 也可以通过  aop的命名空间进去看 spring.handler

 配置的解析过程

XML 解析入口
<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 />
<aop:config> 标签的解析开始,看解析这个标签都做了什么。 查找 aop jar 包的 meta-info 目录,找到对应的 Handler AopNamespaceHandler

config的解析

ConfigBeanDefinitionParser

 对应的属性 等等。

对应的子标签解析 并注册utils 将 aspectj  注册进去 并成为 bean定义。

注册 AutoProxyCreator org.springframework.aop.config.AopConfigUtils#registerOrEscalateApcAsRequired
@Nullable 
public static BeanDefinition registerAspectJAutoProxyCreatorIfNecessary(     
    BeanDefinitionRegistry registry, @Nullable Object source)  
        return registerOrEscalateApcAsRequired(AspectJAwareAdvisorAutoProxyCreator.class, 
        registry, source); 

工厂中有配置的自动代理构造器,则与前面传递的 cls 构造器进行优先级对比

 

 role  范围:内部使用的业务bean   role_infrastructure  org.springframework.aop.config.AopConfigUtils#APC_PRIORITY_LIST 里面装了对应的自动代理创建者的优先等级信息,其实就是索引值

 当在xml中配置了<aop:aspectj-autoproxy>,则会选AnnotationAwareAspectJAutoProxyCreator

 会给我们创建自定义。

 默认就创建的  aspectj的形式。

 创建的advisor

 解析的aspectj

这里比较麻烦一点,应对不同 标签添加不同的  class类型 进行初始化。

AspectJAwareAdvisorAutoProxyCreator 的继承体系 AutoProxyCreator 是一个 BeanPostProcessor 、还是 BeanFactoryAware ,还是 ProxyConfig 。通过 BeanPostProcessor 机制,它将负责创建代理对象。

 

 AbstractAutoProxyCreator实现类

 就是我们前面看到的三个不同优先等级的AutoProxyCreator

 

AopConfig AOP 配置类 ProxyConfig <aop:config> 元素读取配置属性 proxy_target_class expose_proxy ,存放在 ProxyConfig 类中。 AopNamespaceUtils#registerAspectJAutoProxyCreatorIfNecessary

  AspectJ自动代理构建器    属性的处理

 AopConfigUtils.forceAutoProxyCreatorToUseClassProxying

代理的创建 代理创建过程,在 bean 实例创建的时候处理的,很自然就能定位到 createBeanInstance 方法上。

注解中代理类 的方式。

 自动代理的创建者。

AutoProxyCreator 是一个 BeanPostProcessor 、还是 BeanFactoryAware ,还是 ProxyConfig 。通 BeanPostProcessor 机制,它将负责创建代理对象。

aop中代理处理的方法 都是在beanpostprocess中做的功能增强。

AopProxyFactory AopProxyFactory 接口方法

 

 

 判断代理生成的地方去处理。

 织入过程

织入的地方跟创建代理对象是一样的,这里我们来看其中的一个。 AbstractAutoProxyCreator 类中的 getAdvicesAndAdvisorsForBean 方法能找到当前 bean 匹配的 advisor。

 

如何判断Bean要不要被创建代理 

1. 在实例化前进行代理,是否有 TargetSource 的实现 2. 其他,是否有匹配的 Advisor

如何排除advice Bean的代理创建?

wrapIfNecessarypostProcessBeforeInstantiation两个方法都有类似的判断

if (isInfrastructureClass(beanClass) || shouldSkip(beanClass, beanName))      
    this.advisedBeans.put(cacheKey, Boolean.FALSE); return null; 
AbstractAutoProxyCreator#isInfrastructureClass

AspectJAwareAdvisorAutoProxyCreator#shouldSkip方法中判断。  

方法被调用的增强过程

AbstractAdvisorAutoProxyCreator#findEligibleAdvisors方法中  

 

判断是否是aspect

 

 

跟踪 findAdvisorsThatCanApply 方法 最终真正匹配的地方在 AopUtils#canApply

 

 

 

判断是否需要创建aop代理对象。 

 

 匹配到通知 就创建代理。

  都需要做区别开spring中的 ware接口代理的。

 如何组织多个advice执行的?

JDK 动态代理和 CGLib 的实现,都是一样的,通过责任链来处理。 JdkDynamicAopProxy JdkDynamicAopProxy#invoke

都是对class进行匹配。

CglibMethodInvocation继承自ReflectiveMethodInvocationproceed方法不变。 

以上是关于Spring中AOP源码的主要内容,如果未能解决你的问题,请参考以下文章

Spring AOP源码分析

做一个合格的程序猿之浅析Spring AOP源码(十五) 分析JdkDynamicAopProxy的invoke方法

Spring读源码系列之AOP--05---aop常用工具类学习

Spring源码分析AOP源码解析(上篇)

Spring读源码系列之AOP--03---aop底层基础类学习

spring源码分析——Aop的流程