0x5 Spring系列:深入聊一聊 Spring AOP 实现机制【一】
概述
AOP(Aspect-Oriented Programming) 面向切面编程。Spring Aop 在 Spring框架中的地位举足轻重,主要用于实现事务、缓存、安全等功能。本篇主要是对源码进行深度分析。
· Spring AOP
多种代理机制相关核心类介绍。
· Spring Boot
中 AOP 注解方式源码分析。
· Spring Boot
1.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
@Component
public
class
LogableAspect
{
@Pointcut
(
"@annotation(com.springboot2.spring5.springAop.aspect.Logable)"
)
public
void
aspect
()
{
}
@Around
(
"aspect()"
)
public
Object
doAround
(ProceedingJoinPoint point)
throws
Throwable {
//...
Object returnValue = point.proceed(point.getArgs());
//...
return
returnValue;
}
}
这是实际项目中,使用AOP最常见的形式,基于注解实现。如今springboot
大行其道,我们就从springboot
中的EnableAspectJAutoProxy
自动配置开始。
大致流程主要分为三个步骤: 一: 创建AnnotationAwareAspectJAutoProxyCreator
对象 二: 扫描容器中的切面,创建PointcutAdvisor
对象 三: 生成代理类
分别来分析以上三个步骤。
1: 创建 AbstractAutoProxyCreator 对象
基于注解实现的 AOP 默认注册 AbstractAutoProxyCreator 对象实现类为:AnnotationAwareAspectJAutoProxyCreator,来看一下该对象的创建过程。先从spring.factories
开始:
#
Auto
Configure
org
.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
)
public
class
AopAutoConfiguration
{
@Configuration
@EnableAspectJAutoProxy
(proxyTargetClass =
false
)
@ConditionalOnProperty
(prefix =
"spring.aop"
, name =
"proxy-target-class"
, havingValue =
"false"
, matchIfMissing =
false
)
public
static
class
JdkDynamicAutoProxyConfiguration
{
}
@Configuration
@EnableAspectJAutoProxy
(proxyTargetClass =
true
)
@ConditionalOnProperty
(prefix =
"spring.aop"
, name =
"proxy-target-class"
, havingValue =
"true"
, matchIfMissing =
true
)
public
static
class
CglibAutoProxyConfiguration
{
}
}
具体来看:
(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
:
class
AspectJAutoProxyRegistrar
implements
ImportBeanDefinitionRegistrar
{
@Override
public
void
registerBeanDefinitions
(
AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry)
{
//
注册
AnnotationAwareAspectJAutoProxyCreator
AopConfigUtils.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);
}
}
}
}
@Nullable
public
static
BeanDefinition registerAspectJAnnotationAutoProxyCreatorIfNecessary(BeanDefinitionRegistry registry,
@Nullable
Object
source) {
return
registerOrEscalateApcAsRequired(AnnotationAwareAspectJAutoProxyCreator.
class
, registry, source);
}
上述代码可以看到注册了一个切面相关BeanDefinition
,正是上面提到的类:AnnotationAwareAspectJAutoProxyCreator
,并设置了代理方式配置变量: proxyTargetClass
,默认为true。
这里只是创建BeanDefinition
,并没有实例化和初始化该对象。那什么时候会触发呢?
上面的 uml 图可以看到,该类继承的顶层接口为 BeanPostProcessor
。我们知道BeanPostProcessor
实现类会提前初始化,由PostProcessorRegistrationDelegate
触发,具体细节之前博客有提到:
SpringBoot2 | @SpringBootApplication注解 自动化配置流程源码分析(三)
该类又继承BeanFactoryAware
,所以在其在实例化 bean 后,会触发setBeanFactory()
方法,最终会触发initBeanFactory
方法:
@Override
protected
void
initBeanFactory
(ConfigurableListableBeanFactory beanFactory)
{
super
.initBeanFactory(beanFactory);
if
(
this
.aspectJAdvisorFactory ==
null
) {
//advisor
工厂类
this
.aspectJAdvisorFactory =
new
ReflectiveAspectJAdvisorFactory(beanFactory);
}
//
用于创建
advisor
this
.aspectJAdvisorsBuilder =
new
BeanFactoryAspectJAdvisorsBuilderAdapter(beanFactory,
this
.aspectJAdvisorFactory);
}
最终 Advisor 对象就是由aspectJAdvisorsBuilder 生成。
至此,AnnotationAwareAspectJAutoProxyCreator BeanDefinition
创建完毕。
- 点赞
- 收藏
- 关注作者
评论(0)