Zookeeper安装 numpy laravel sorting dictionary animation directory callback mui linux自动获取ip mysql错误代码1064 mysql将时间戳转换成日期 python数据格式 数据库学习 java字符串查找 java包名 java数组排序 java程序设计教程 幽城幻剑录五内 maxtoc4d 编辑软件 linux定时任务 数组求和 一键隐藏 俄罗斯方块代码 ip地址切换器 winsxs可以删除吗 魔兽天龙八部 爱奇艺视频下载到电脑 小米开发者选项 ps虚化背景 熊猫关键词 layout软件 括号符号大全 urlpattern editplus中文版 视频采集软件 未能创建视频预览 ps制作动画 手机模拟器电脑版
当前位置: 首页 > 学习教程  > 编程语言

Spring源码分析_4 Spring AOP原理分析

2021/1/22 23:07:12 文章标签:

Spring源码分析_4 Spring AOP原理分析 作者:田超凡 版权所有,严禁复制转载 1 SpringAOP基本概念 Spring AOP面向切面编程,是Spring核心体系中的第二大核心思想,它的核心设计理念是基于代理设计模式,采用动态代理实现…

                                                              Spring源码分析_4 Spring AOP原理分析

                                                                                                                                                                                                                                                                                   作者:田超凡

                                                                                                                                                                                                                                                                                   版权所有,严禁复制转载

1 SpringAOP基本概念

Spring AOP面向切面编程,是Spring核心体系中的第二大核心思想,它的核心设计理念是基于代理设计模式,采用动态代理实现代码解耦,将业务和与业务无关的横切逻辑完全剥离开来(日志、权限控制、异常重试、拦截、执行性能监测),使得开发人员能专注业务逻辑层面的开发,对于这些横切逻辑只需要定义一套通用的AOP切面、切入点、连接点、符合各类场景下的增强处理实现即可,在业务层面和横切逻辑的融合层面真正做到完全解耦,实现高内聚低耦合、单元化动态化SpringAOP配置,真正做到即拆即用。

AOP指的是面向切面编程,是面向对象编程(OOP)的一定维度的扩展和补充,而不是重新发明一个轮子。AOP的主要作用是把从业务逻辑中的日志记录、性能监测、权限控制等代码剥离出来,形成一个横切逻辑,也就是切面(Aspect)。在目标方法执行过程中的特定时间点,由程序启动时在这些目标方法上动态加入某些功能(或者说加入增强处理),把这些动态加入的多个功能封装在一起,就形成了理想意义上的横切逻辑,即切面(Aspect)。AOP的设计思想彻底摒弃了传统硬编码写死的方式而造成的代码耦合度高的问题,使得代码扩展性提高了很多。与此同时,提高了增强方法(也就是动态加入的功能)的扩展性和维护性,也更加符合OOP的核心思想和目标:高内聚,低耦合。

 

SpringAOP使用和配置流程:

  1. 定义@Aspect标注的AOP切面类,作为横切逻辑的空间单元,封装各类需要处理的切入点描述和各类增强处理方法的具体实现。切入点指的是连接点的匹配规则,满足切入点规则的方法将会被执行前后动态织入增强处理,核心原理是SpringAOP容器启动时会过滤出IOC容器中所有已经注册的Bean中的@Aspect切面类,读取@Pointcut切入点规则,递归扫描满足切入点规则的Bean,创建其代理实例,这样在调用目标方法执行时就会执行代理实例的代理方法,从而实现在目标方法执行前后动态加入新的功能,进行增强处理。
  2. SpringConfig配置类中@EnableAspectJAutoProxy启用SpringAOP即可

Spring AOP的基本术语:

Target 目标实例:即需要代理的目标执行实例

Proxy 代理实例:即替代目标实例进行操作的实例

JoinPoint 连接点:目标执行实例需要执行的方法在真正执行时的特定时间片,或者可以理解为跟切入点特征描述比较匹配的目标方法。

PointCut 切入点:代理实例需要代理的目标实例的方法特征,是一个特征描述,目标实例可以存在多个和切入点描述的特征匹配的目标方法作为代理目标方法。

Advice 增强:横切逻辑中需要对目标方法加入的功能,以方法为单位,切面中的一个方法就是一个增强。

Advisor 切面:多个增强方法组成的一个横切逻辑。

Weaving 织入:将切面中的增强和目标方法执行时结合的这一个过程,强调的是增强方法和目标方法结合的过程,作用单位是方法。

Introduction 引入:将切面中的增强和目标类中的符合切入点描述特征的方法结合的过程,强调的是增强方法和目标类中符合切入点特征描述的结合过程,作用单位是类。

 

代理设计模式

  1. 代理设计模式的核心思想是替代处理,通俗的说,就是找一个替身来做本属于原身要做的事,也可以形象的理解为“替罪羊”,但是很明显这种形容也不是很恰当,如果代理设计模式运用在合适的场景下,并且能发挥出好的功效,代理模式起码也是“占为己有”。Spring AOP实际上就是代理设计模式的一种实现方式。
  2. 静态代理和动态代理
  3. 静态代理:定义XXXProxy.java作为静态代理类来对目标接口中的方法进行代理。但是有一个不可忽视的问题就是,如果需要代理的目标接口方法发生了更改,则除了该接口的实现类中的方法需要发生更改,同时该静态代理类中的代理方法也需要调整和更改,代理的目标接口随便的一个方法发生改动,就会牵一发动全身(动实现类,动静态代理类),如果这个接口中的方法数量庞大,比如100个方法,那改动量就不言而喻了,这样很明显代码的扩展性问题还是存在瓶颈,传统的静态代理模式仅适用于代理的目标接口方法不是很多的情况。
  4. 动态代理:定义一个通用的代理类,代理目标是某个接口或普通类,通过反射来对所有需要代理的目标接口中的方法进行统一代理,当代理目标中的方法发生变化,对于动态代理类而言,他只关心代理的目标本身是否发生变化,即代理的接口和类名称是否发生变化,也就是说当代理的目标接口或类中的方法不论发生什么改动,改动多少次,都不会影响定义的这个动态代理类中的代码,只需要调整和改动代理的目标接口对应的实现类中的代码即可。这种方式很明显提高了代码扩展性和维护性,从容应对代理目标内部发生的任何变化,都不会影响动态代理类本身,这也是代理设计模式的核心所在。

 

2 SpringAOP原理图

SpringAOP工作原理图

 

 

SpringAOP源码实现原理图

 

 

 

3 SpringAOP原理分析

1 SpringConfig配置类通过@EnableAspectJAutoProxy开启SpringAOP

2 AspectJAutoProxyRegistrar -> ImportBeanDefinitionRegistrar SpringAOP动态代理注册器,注册AnnotationAwareAspectJAutoProxyCreator

beanDefinistionRegistry.register(beanId,bean);

BeanId:org.springframework.aop.config.internalAutoProxyCreator

BeanClass AnnotationAwareAspectJAutoProxyCreator

3 AnnotationAwareAspectJAutoProxyCreator 负责创建代理实例,是执行SpringAOP代理策略的核心类,其继承关系如下:

AnnotationAwareAspectJAutoProxyCreator

  • AspectJAwareAdvisorAutoProxyCreator
  • AbstractAdvisorAutoProxyCreator
  • AbstractAutoProxyCreator
  • SmartInstantiationAwareBeanPostProcessor
  • InstantiationAwareBeanPostProcessor
  • BeanPostProcessor

 

4 被代理目标对象在初始化的时候,被AbstractAutoProxyCreator拦截,使用ProxyFactory代理工厂创建代理实例。

创建代理实例时先判断该被代理对象是否有被有实现过接口,如果有实现过接口就使用jdk动态代理,如果没有实现接口则使用cglib动态代理。

(创建匹配代理策略的对应的代理实例JDKDynamicAopProxy/CglibAopProxy)

5当我们调用目标方法的时候,会执行对应代理实例JdkDynamicAopProxy/CglibAopProxy的invoke方法(代理方法),在invoke方法中,如果已经声明了切面类和增强处理方法,会调用ReflectionMethodInvocation中使用递归算法+责任链模式,通过预先封装好的SpringAOP作用链,循环遍历执行MethodInterceptor(每个增强/通知)的invoke方法,如果没有声明切面类和增强处理方法,那么就会直接调用Proxy.newProxyInstance()/Enhancer.create创建对应的JDK/CGLIB代理实例

(SpringAOP主要是基于调用链实现各类增强处理针对目标连接点方法的织入,基于代理模式和责任链模式实现,使用ReflectionMethodInvocation完成SpringAOP调用链的组装和调用)

注意:SpringAOP各类自定义增强和内置增强的继承关系:

自定义各类前置、后置、异常抛出、环绕、最终增强、事务

(MethodBeforeAdvice、AfterReturningAdvice、AfterThrowingAdvice、AroundAdvice、AfterAdvice、TransactionInterceptor) -> MethodInterceptor -> Interceptor -> Advice

 

4 SpringAOP源码分析

1 在SpringConfig配置类使用@EnableAspectJAutoProxy即可开启Spring AOP,该注解引入了AOP注册核心处理器的工具类AspectJAutoProxyRegistrar

注意:AspectJAutoProxyRegistrar 是一个AOP核心处理器的注册器,重写ImportBeanDefinitionRegistrar的registerBeanDefinitions()注册AOP核心处理器

 

 

 

2 调用工具类注册AnnotationAwareAspectJAutoProxyCreator核心处理器实现AOP代理类和代理实例的创建和注册,注册完之后会解析核心处理器的Bean定义并根据注解上指定的配置值来强制覆盖默认策略,也就是说如果使用@EnableAspectJAutoProxy注解指定了值,则会采用指定的值来生效配置,但是指定的值如果不正确在创建代理的时候会报错。比如proxyTargetClass设置为true,则会强制采用cglib动态代理模式,这种情况下如果需要创建JDK动态代理实例就会报错,因为JDK动态代理实例要求代理目标必须实现了接口

 

 

3 先校验AnnotationAwareAspectJAutoProxyCreator的Bean定义是否已注册,如果已注册则需要排序,如果没注册过则注册AnnotationAwareAspectJAutoProxyCreator的Bean定义到IOC容器中

 

 

4 AOP核心处理器注册到IOC容器中之后,当初始化被调用目标Bean实例之后,会调用AbstractAutoProxyCreator进行拦截,调用postProcessAfterInitialization()后置增强来替代BeanPostProcessor中默认的postProcessAfterInitialization()

继承关系如下:

AnnotationAwareAspectJAutoProxyCreator

AspectJAwareAdvisorAutoProxyCreator

AbstractAdvisorAutoProxyCreator

AbstractAutoProxyCreator

SmartInstantiationAwareBeanPostProcessor

InstantiationAwareBeanPostProcessor

BeanPostProcessor

 

 

5 AbstractAutoProxyCreator拦截到目标Bean初始化完成之后,调用postProcessAfterInitialization()进行后置增强处理

在该方法中,会先调用getCacheKey根据beanName获取beanId,这是一个适配器方法,可以适配目标Bean是普通Bean和基于FactoryBean工厂类创建的Bean,他们在IOC容器中注册时生成的beanId是完全不一样的,FactoryBean创建的Bean在生成的beanId中会加入前缀标志

 

 

其次,会校验代理目标Bean是否已经提前执行完后置增强,如果已经执行完,则不会重新执行,此时需要排查目标Bean是否定义了自定义的BeanPostProcessor后置拦截,一般来说,需要被SpringAOP容器创建代理的目标Bean是不能定义自定义的BeanPostProcessor实现后置拦截的。

 

 

调用wrapIfNecessary()方法开始加载增强/通知,创建代理实例

 

 

调用getAdvicesAndAdvisorsForBean()获取需要生效的AOP切面

 

 

 

获取IOC容器中已经注册的AOP切面Bean,如果切面Bean还在创建中获取切面Bean会报错,不加载还在创建过程中的AOP切面Bean

 

 

 

AOP切面加载完成之后,会调用createProxy()基于ProxyFactory代理工厂创建代理实例

 

 

代理模式默认采用JDK动态代理(proxyTargetClass=false),根据代理模式的不同创建不同的代理实例实现JDKDynamicAopProxy/CglibAopProxy

如果是默认的JDK动态代理,需要调用evaluateProxyInterfaces()解析被代理的目标Bean实现的接口

如果目标Bean实现的接口Bean已注册到IOC容器中,则获取目标Bean实现的所有接口,如果目标Bean没有实现接口或者实现的接口Bean在IOC容器中不存在,则需要采用CGLIB动态代理创建代理实例,设置proxyTargetClass=true

 

 

 

调用ProxyFactory的getProxy()创建基于对应代理模式的代理实例

 

 

 

这里以JDK动态代理模式为例进行分析。调用JDKDynamicAopProxy代理实例的getProxy()方法创建JDK代理实例,后续再调用目标Bean的方法时,实际就会执行JDKDynamicAopProxy代理实例的代理方法invoke()

 

 

 

在执行代理方法时,首先会基于工厂模式+责任链模式调用DefaultAdvisorChainFactory加载和组装SpringAOP作用链,作用链中存放的都是需要给当前目标Bean织入增强处理的增强类(通知类),后面会统一封装成ReflectiveMethodInvocation作为SpringAOP作用链执行主体,调用SpringAOP作用链中每一个增强类(MethodInterceptor)的增强方法(invoke),这些增强方法默认提供的都是空实现,如果存在自定义的增强处理类继承或重写了这些增强方法,那么根据里氏替换原则这里就会执行相应增强子类的invoke方法

 

 

 

 

封装好SpringAOP处理链之后,会校验处理链中是否为空,如果非空则认为有增强需要执行,如果没有则直接创建默认的代理实例,如果处理链有处理环节(有增强)则会创建SpringAOP处理链具体的执行对象ReflectiveMethodInvocation来执行SpringAOP处理链。

基于工厂模式+责任链模式实现,核心算法是递归

 

 

 

5 Spring AOP实现声明式事务管理实现原理分析

  1. 开启@EnableTransactionManagement开启事务注解
  2. @Import(TransactionManagementConfigurationSelector.class)
  3. 继续加载AutoProxyRegistrarProxyTransactionManagementConfiguration对象
  4. AutoProxyRegistrar会将该类InfrastructureAdvisorAutoProxyCreator注册ioc容器
  5. InfrastructureAdvisorAutoProxyCreator祖宗是BeanPostProcessor,所以得知当bean对象初始化的时该对象与Aop实现一样的功能。

InfrastructureAdvisorAutoProxyCreator –

AbstractAdvisorAutoProxyCreator

AbstractAutoProxyCreator 拦截Bean初始化后的后置增强postProcessAfterInitialization,根据代理目标是否实现了接口,@EnableAspectJAutoProxy配置的proxyTargetClass的值决定采用JDK/CGLIB动态代理,创建相应的代理实例JDKDynamicAopProxy/CglibAopProxy

SmartInstantiationAwareBeanPostProcessor

InstantiationAwareBeanPostProcessor

BeanPostProcessor

6 Ioc容器中注册InfrastructureAdvisorAutoProxyCreator

7 ProxyTransactionManagementConfiguration配置类的对象注册到IOC容器中。

8 TransactionInterceptor 祖宗是MethodInterceptor

TransactionInterceptor -> MethodInterceptor -> Interceptor -> Advice

8.  当SpringAop链在调用时候,会执行到TransactionInterceptor的invoke

 

if (txAttr == null || !(tm instanceof CallbackPreferringPlatformTransactionManager)) {
  
// 开启事务
  
TransactionInfo txInfo = createTransactionIfNecessary(tm, txAttr, joinpointIdentification);
   Object retVal =
null;
  
try {
  
  // 执行目标方法
     
retVal = invocation.proceedWithInvocation();
   }
  
catch (Throwable ex) {
   
 // 回滚当前事务
     
completeTransactionAfterThrowing(txInfo, ex);
     
throw ex;
   }
  
finally {
      cleanupTransactionInfo(txInfo);
   }

//提交当前事务
   commitTransactionAfterReturning(txInfo);
  
return retVal;
}

 

 

TransactionInterceptor封装了事务的开启、提交、回滚。

综述:Spring AOP实现声明式事务管理总的来说基于Spring AOP环绕增强+手动事务实现

通过事务增强类TransactionInterceptor封装目标方法的执行,在目标方法执行前后加入事务操作(commit/rollback),在拦截到目标Bean初始化完毕之后,调用InfrastructureAdvisorAutoProxyCreator -> AbstractAdvisorAutoProxyCreator -> AbstractAutoProxyCreator postProcessAfterInitialization() -> getProxy() 创建代理实例并在执行代理方法时基于责任链模式依次调用SpringAOP作用链中的每一个增强的invoke执行(List<MethodInterceptor> methodInterceptors)

 

6 Spring AOP实现声明式事务管理源码分析

1 在SpringConfig配置类中使用@EnableTransactionManagement开始声明式事务管理,引入TransactionManagementConfigurationSelector

 

 

2 TransactionManagementConfigurationSelector 实现了ImportSelector,在注册Bean定义的方法中会加载AutoProxyRegistrarProxyTransactionManagementConfiguration

 

 

AutoProxyRegistrar 实现了 ImportBeanDefinitionRegistrar

 

 

在注册Bean定义的方法中,调用AopConfigUtils工具类创建实现声明式事务管理的核心处理器InfrastructureAdvisorAutoProxyCreator

 

 

 

获取和注册InfrastructureAdvisorAutoProxyCreator的Bean定义

 

 

SpringAOP声明式事务管理核心处理器InfrastructureAdvisorAutoProxyCreator -> AbstractAdvisorAutoProxyCreator -> AbstractAutoProxyCreator

所以最终也会调用AbstractAutoProxyCreator 的postProcessAfterInitialization()拦截目标Bean初始化完成,在后置增强实现方法中创建代理实例,调用代理方法时调用SpringAOP的作用链(ReflectiveMethodInvocation)中的TransactionInterceptor的invoke方法实现事务处理。

调用AbstractAutoProxyCreator的postProcessAfterInitialization()拦截目标Bean初始化完成并在后置增强方法中创建代理实例的实现细节和流程见上文Spring AOP实现原理和源码分析

 

 


本文链接: http://www.dtmao.cc/news_show_630869.shtml

附件下载

相关教程

    暂无相关的数据...

共有条评论 网友评论

验证码: 看不清楚?