0x5 Spring系列:深入聊一聊 Spring AOP 实现机制【一】
概述
AOP(Aspect-Oriented Programming) 面向切面编程。Spring Aop 在 Spring框架中的地位举足轻重,主要用于实现事务、缓存、安全等功能。本篇主要是对源码进行深度分析。
· Spring AOP 多种代理机制相关核心类介绍。
· Spring Boot 中 AOP 注解方式源码分析。
· Spring Boot1.x版本和 2.x版本 AOP 默认配置的变动。
一: Spring AOP多种代理机制核心类
先介绍一些Spring Aop中一些核心类,大致分为三类:
· advisorCreator:代理机制,抽象类AbstractAutoProxyCreator的每个实现类代表着一种代理机制。默认情况下只使用一种代理机制。 继承 spring ioc的扩展接口 beanPostProcessor,主要用来扫描获取 advisor。
· advisor:顾问的意思,advisor是Spring中切面的体现形式,封装了spring aop中的切点和通知。
· advice:通知,也就是 Spring AOP 中增强的方法。
以上三种核心类,来看对应的 UML图。
advisorCreator:
· AbstractAutoProxyCreator:代理机制抽象类,Spring 为Spring AOP 模块暴露的扩展类,也是 AOP 中最核心的类。Nepxion Matrix 框架便是基于此类对AOP进行扩展和增强。
· BeanNameAutoProxyCreator:根据指定名称创建代理对象(阿里大名鼎鼎的连接池框架druid也基于此类做了扩展)。通过设置 advisor,可以对指定的 beanName 进行代理。支持模糊匹配。
· AbstractAdvisorAutoProxyCreator:功能比较强大,默认扫描所有Advisor的实现类。相对于根据Bean名称匹配,该类更加灵活。动态的匹配每一个类,判断是否可以被代理,并寻找合适的增强类,以及生成代理类。
· DefaultAdvisorAutoProxyCreator:AbstractAdvisorAutoProxyCreator的默认实现类。可以单独使用,在框架中使用AOP,尽量不要手动创建此对象。
· AspectJAwareAdvisorAutoProxyCreator:Aspectj的实现方式,也是Spring Aop中最常用的实现方式,如果用注解方式,则用其子类AnnotationAwareAspectJAutoProxyCreator。
· AnnotationAwareAspectJAutoProxyCreator:目前最常用的AOP使用方式。spring aop 开启注解方式之后,该类会扫描所有@Aspect()标准的类,生成对应的adviosr。目前SpringBoot框架中默认支持的方式,自动配置。
advisor:
· StaticMethodMatcherPointcut:静态方法切面,抽象类。定义了一个classFilter,通过重写getClassFilter()方法来指定切面规则。另外实现了StaticMethodMatcher接口,通过重写matches来指定方法匹配规则。
· StaticMethodMatcherPointcutAdvisor:静态方法匹配切面顾问,同未抽象类,扩展了切面排序方法。
· NameMatchMethodPointcut:名称匹配切面,通过指定方法集合变量mappedNames,模糊匹配。
· NameMatchMethodPointcutAdvisor:方法名称切面顾问,内部封装了NameMatchMethodPointcut,通过设置方法名称模糊匹配规则和通知来实现切面功能。
· RegexpMethodPointcutAdvisor:正则表达式切面顾问,可设置多个正则表达式规则,通过内部封装的JdkRegexpMethodPointcut解析正则表达式。
· DefaultPointcutAdvisor:默认切面顾问,比较灵活。可自由组合切面和通知。
· InstantiationModelAwarePointcutAdvisorImpl:springboot自动装配的顾问类型,也是最常用的一种顾问实现。在注解实现的切面中,所有@Aspect注释的类,都会被解析成该对象。
advice:
· AspectJMethodBeforeAdvice:前置通知,AspectJ中 before 属性对应的通知(@Before标注的方法会被解析成该通知),在切面方法执行之前执行。
· AspectJAfterReturningAdvice:后置通知,AspectJ中 afterReturning 属性对应的通知(@AfterReturning 标注的方法会被解析成该通知),在切面方法执行之后执行,如果有异常,则不执行。
注意:该通知与AspectJMethodBeforeAdvice对应。
· AspectJAroundAdvice:环绕通知,AspectJ中 around 属性对应的通知(@Around标注的方法会被解析成该通知),在切面方法执行前后执行。
· AspectJAfterAdvice:返回通知,AspectJ中 after 属性对应的通知(@After 标注的方法会被解析成该通知),不论是否异常都会执行。
可以看出 Spring AOP 提供的实现方式很多,但是殊途同归。
具体使用方式已上传至 github:
https://github.com/admin801122/springboot2-spring5-studying
二:Spring Boot 中AOP注解方式源码分析
Spring Aop使用方式很多,从上面的 API 也可以看出。本篇就基于最常用的注解实现方式,对源码深入分析。
@Aspect@ComponentpublicclassLogableAspect{@Pointcut("@annotation(com.springboot2.spring5.springAop.aspect.Logable)")publicvoidaspect(){}@Around("aspect()")publicObjectdoAround(ProceedingJoinPoint point)throwsThrowable {//...Object returnValue = point.proceed(point.getArgs());//...returnreturnValue;}}
这是实际项目中,使用AOP最常见的形式,基于注解实现。如今springboot大行其道,我们就从springboot中的EnableAspectJAutoProxy自动配置开始。
大致流程主要分为三个步骤: 一: 创建AnnotationAwareAspectJAutoProxyCreator对象 二: 扫描容器中的切面,创建PointcutAdvisor对象 三: 生成代理类
分别来分析以上三个步骤。
1: 创建 AbstractAutoProxyCreator 对象
基于注解实现的 AOP 默认注册 AbstractAutoProxyCreator 对象实现类为:AnnotationAwareAspectJAutoProxyCreator,来看一下该对象的创建过程。先从spring.factories开始:
#AutoConfigureorg.springframework.boot.autoconfigure.aop.AopAutoConfiguration,\
@Configuration@ConditionalOnClass({ EnableAspectJAutoProxy.class, Aspect.class, Advice.class,AnnotatedElement.class})@ConditionalOnProperty(prefix ="spring.aop", name ="auto", havingValue ="true", matchIfMissing =true)publicclassAopAutoConfiguration{@Configuration@EnableAspectJAutoProxy(proxyTargetClass =false)@ConditionalOnProperty(prefix ="spring.aop", name ="proxy-target-class", havingValue ="false", matchIfMissing =false)publicstaticclassJdkDynamicAutoProxyConfiguration{}@Configuration@EnableAspectJAutoProxy(proxyTargetClass =true)@ConditionalOnProperty(prefix ="spring.aop", name ="proxy-target-class", havingValue ="true", matchIfMissing =true)publicstaticclassCglibAutoProxyConfiguration{}}
具体来看:
(1)该配置类的加载前提是什么?
@ConditionalOnClass({EnableAspectJAutoProxy.class,Aspect.class,Advice.class,AnnotatedElement.class})
条件注解依赖的配置类均被引入到spring-boot-starter-aop中,只需引入该依赖即可自动装配。
而且可以看到spring.aop.auto默认为true,并不需要手动开启。
所以很多同学在springboot项目中使用 aop 的时候,习惯在启动类上引入@EnableAspectJAutoProxy,其实完全不必要。保证项目中有spring-boot-starter-aop依赖即可。
(2)上述代码通过spring.aop.proxy-target-class变量来控制proxyTargetClass的变量,最终都会加载@EnableAspectJAutoProxy配置。spring.aop.proxy-target-class默认为true,该变量相当关键,控制 spring aop 代理类的生成方式,具体后面详细介绍。
继续跟进EnableAspectJAutoProxy:
classAspectJAutoProxyRegistrarimplementsImportBeanDefinitionRegistrar{@OverridepublicvoidregisterBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry){//注册AnnotationAwareAspectJAutoProxyCreatorAopConfigUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(registry);AnnotationAttributes enableAspectJAutoProxy =AnnotationConfigUtils.attributesFor(importingClassMetadata, EnableAspectJAutoProxy.class);//将aop代理方式相关的变量设置到AopConfigUtils,创建代理类时会读取变量if(enableAspectJAutoProxy !=null) {if(enableAspectJAutoProxy.getBoolean("proxyTargetClass")) {AopConfigUtils.forceAutoProxyCreatorToUseClassProxying(registry);}if(enableAspectJAutoProxy.getBoolean("exposeProxy")) {AopConfigUtils.forceAutoProxyCreatorToExposeProxy(registry);}}}}
@NullablepublicstaticBeanDefinition registerAspectJAnnotationAutoProxyCreatorIfNecessary(BeanDefinitionRegistry registry,@NullableObjectsource) {returnregisterOrEscalateApcAsRequired(AnnotationAwareAspectJAutoProxyCreator.class, registry, source);}
上述代码可以看到注册了一个切面相关BeanDefinition,正是上面提到的类:AnnotationAwareAspectJAutoProxyCreator,并设置了代理方式配置变量: proxyTargetClass,默认为true。
这里只是创建BeanDefinition,并没有实例化和初始化该对象。那什么时候会触发呢?
上面的 uml 图可以看到,该类继承的顶层接口为 BeanPostProcessor。我们知道BeanPostProcessor实现类会提前初始化,由PostProcessorRegistrationDelegate触发,具体细节之前博客有提到:
SpringBoot2 | @SpringBootApplication注解 自动化配置流程源码分析(三)
该类又继承BeanFactoryAware,所以在其在实例化 bean 后,会触发setBeanFactory()方法,最终会触发initBeanFactory方法:
@OverrideprotectedvoidinitBeanFactory(ConfigurableListableBeanFactory beanFactory){super.initBeanFactory(beanFactory);if(this.aspectJAdvisorFactory ==null) {//advisor工厂类this.aspectJAdvisorFactory =newReflectiveAspectJAdvisorFactory(beanFactory);}//用于创建advisorthis.aspectJAdvisorsBuilder =newBeanFactoryAspectJAdvisorsBuilderAdapter(beanFactory,this.aspectJAdvisorFactory);}
最终 Advisor 对象就是由aspectJAdvisorsBuilder 生成。
至此,AnnotationAwareAspectJAutoProxyCreator BeanDefinition创建完毕。
- 点赞
- 收藏
- 关注作者
评论(0)