共计 14120 个字符,预计需要花费 36 分钟才能阅读完成。
前言
本篇文章是 SpringAOP 的源码学习分享,分为高低两篇,本篇是对 SpringAOP 中切面织入业务 bean 时为业务 bean 生成动静代理对象的这一块的源码学习。
注释
一. 示例工程搭建
通过引入 Springboot 来实现引入 Spring 的相干依赖,依赖项如下所示。
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
</dependency>
</dependencies>
应用的 Springboot 版本为 2.4.1,对应的Spring 版本为5.3.2。
首先自定义一个注解,用于在切点中定位到指标办法,如下所示。
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface MyMethod {}
而后定义业务接口和实现类,如下所示。
public interface IMyService {void executeTask(String message);
void tempExecute(String message);
}
@Service
public class MyService implements IMyService {
@Override
@MyMethod
public void executeTask(String message) {System.out.println(message);
}
@Override
public void tempExecute(String message) {executeTask(message);
}
}
而后定义一个切面,已知 切面 = 切点 + 告诉
,在本示例工程中,切点是所有由@MyMethod
注解润饰的办法,并且抉择前置告诉和后置告诉,如下所示。
@Aspect
@Component
public class MyAspect {@Pointcut("@annotation(com.learn.aop.aspect.MyMethod)")
public void myMethodPointcut() {}
@Before(value = "myMethodPointcut()")
public void commonBeforeMethod(JoinPoint joinPoint) {System.out.println("Common before method.");
}
@After(value = "myMethodPointcut()")
public void commonAfterMethod(JoinPoint joinPoint) {System.out.println("Common after method.");
}
}
自定义一个配置类,和下面所有类放在同一包门路下,如下所示。
@ComponentScan
@EnableAspectJAutoProxy
public class MyConfig {}
最初编写一个测试程序,如下所示。
public class MyTest {public static void main(String[] args) {
ApplicationContext applicationContext
= new AnnotationConfigApplicationContext(MyConfig.class);
IMyService iMyService = applicationContext.getBean(IMyService.class);
iMyService.tempExecute("Real method execute.");
iMyService.executeTask("Real method execute.");
}
}
运行测试程序,打印如下。
能够看到运行 executeTask()
办法时,切面逻辑失效了。
二. 时序图
SpringAOP中动静代理对象的生成,能够分为两个大的步骤。
- 步骤一 :将作用于以后bean 的告诉获取进去,失去 告诉链;
- 步骤二 :基于告诉链为以后bean 生成 AOP 动静代理对象,并依据配置和指标 bean 决定是应用 CGLIB 动静代理还是 JDK 动静代理。
告诉链能够示意如下。
List<Advisor> chain
Advisor
接口是 SpringAOP 中对告诉的一个顶层形象,其有两个子接口,类图如下所示。
PointcutAdvisor
是对切点相干的告诉的形象,能够将 PointcutAdvisor
了解为对 告诉办法 和切点 的封装,因为本文的示例工程中的切面中的告诉全副是切点相干的告诉,所以无非凡阐明时,Advisor
均指 PointcutAdvisor
,并且也能够不太谨严的将Advisor
称为告诉。
在理清了概念之后,上面给出时序图,时序图有两张,一张是告诉链的获取时序图,一张是 AOP 动静代理对象的生成时序图,如下所示。
- 告诉链的获取时序图。
- AOP动静代理对象的生成时序图。
后续源码的剖析能够联合上述时序图进行了解。
三. SpringAOP 动静代理对象生成工夫点
在示例工程中,如果通过断点调试的办法,察看 iMyService 字段,能够发现其是一个动静代理对象,如下所示。
在 bean 生命周期中,bean的实例化,属性注入和初始化都在 AbstractAutowireCapableBeanFactory
的doCreateBean()
办法中,在该办法中会先调用 createBeanInstance()
办法将 bean 实例化进去,而后调用 populateBean()
办法为 bean 实例实现属性注入,最初调用 initializeBean()
办法来初始化 bean。上面看一下initializeBean()
办法的实现。
protected Object initializeBean(String beanName, Object bean, @Nullable RootBeanDefinition mbd) {
......
if (mbd == null || !mbd.isSynthetic()) {// 调用 BeanPostProcessors 的 postProcessBeforeInitialization()办法
wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
}
......
if (mbd == null || !mbd.isSynthetic()) {// 调用 BeanPostProcessors 的 postProcessAfterInitialization()办法
wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
}
return wrappedBean;
}
在初始化 bean 的时候,就会调用到 BeanPostProcessors
(bean 后置处理器)的 postProcessBeforeInitialization()
和postProcessAfterInitialization()
办法,在 BeanPostProcessors
的实现类 AnnotationAwareAspectJAutoProxyCreator
的postProcessAfterInitialization()
办法中,就会为 bean 织入切面(为 bean 生成动静代理对象)。
上面给出 AnnotationAwareAspectJAutoProxyCreator
的类图。
四. 告诉链的获取
上一节中已知,在 BeanPostProcessors
的实现类 AnnotationAwareAspectJAutoProxyCreator
的postProcessAfterInitialization()
办法中,就会为 bean 织入切面(为 bean 生成动静代理对象),那么就以 AnnotationAwareAspectJAutoProxyCreator
的postProcessAfterInitialization()
办法为入口,开始剖析源码。其实 AnnotationAwareAspectJAutoProxyCreator
没有对 postProcessAfterInitialization()
办法做实现,那么理论调用到的是 AnnotationAwareAspectJAutoProxyCreator
父类 AbstractAutoProxyCreator
的postProcessAfterInitialization()
办法,如下所示。
public Object postProcessAfterInitialization(@Nullable Object bean, String beanName) {if (bean != null) {Object cacheKey = getCacheKey(bean.getClass(), beanName);
if (this.earlyProxyReferences.remove(cacheKey) != bean) {
// 如果 bean 是切面作用指标,就为 bean 生成动静代理对象
return wrapIfNecessary(bean, beanName, cacheKey);
}
}
return bean;
}
持续看 wrapIfNecessary()
办法的实现,如下所示。
protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {if (StringUtils.hasLength(beanName) && this.targetSourcedBeans.contains(beanName)) {return bean;}
if (Boolean.FALSE.equals(this.advisedBeans.get(cacheKey))) {return bean;}
if (isInfrastructureClass(bean.getClass()) || shouldSkip(bean.getClass(), beanName)) {this.advisedBeans.put(cacheKey, Boolean.FALSE);
return bean;
}
// 把作用在以后 bean 的告诉获取进去
Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null);
if (specificInterceptors != DO_NOT_PROXY) {this.advisedBeans.put(cacheKey, Boolean.TRUE);
// 为以后 bean 生成动静代理对象
Object proxy = createProxy(bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource(bean));
this.proxyTypes.put(cacheKey, proxy.getClass());
// 返回以后 bean 的动静代理对象
return proxy;
}
this.advisedBeans.put(cacheKey, Boolean.FALSE);
return bean;
}
wrapIfNecessary()
办法会先将作用于以后 bean 的告诉链获取进去,而后再调用 createProxy()
办法为以后 bean 创立动静代理对象,那么本大节重点剖析 getAdvicesAndAdvisorsForBean()
办法的实现。getAdvicesAndAdvisorsForBean()
实现如下。
protected Object[] getAdvicesAndAdvisorsForBean(Class<?> beanClass, String beanName, @Nullable TargetSource targetSource) {
// 将作用于以后 bean 的告诉获取进去,并且告诉会被封装成 Advisor 的实现类
List<Advisor> advisors = findEligibleAdvisors(beanClass, beanName);
if (advisors.isEmpty()) {return DO_NOT_PROXY;}
return advisors.toArray();}
持续看 findEligibleAdvisors()
办法,如下所示。
protected List<Advisor> findEligibleAdvisors(Class<?> beanClass, String beanName) {
// 找到容器中所有由 @Aspect 注解润饰的切面,并将切面中的每个告诉办法都封装成一个 Advisor 的实现类
List<Advisor> candidateAdvisors = findCandidateAdvisors();
// 在 candidateAdvisors 中将作用于以后 bean 的 Advisor 获取进去
List<Advisor> eligibleAdvisors = findAdvisorsThatCanApply(candidateAdvisors, beanClass, beanName);
extendAdvisors(eligibleAdvisors);
if (!eligibleAdvisors.isEmpty()) {
// 对 Advisor 进行排序
eligibleAdvisors = sortAdvisors(eligibleAdvisors);
}
return eligibleAdvisors;
}
findEligibleAdvisors()
办法中会先调用到 AnnotationAwareAspectJAutoProxyCreator
的findCandidateAdvisors()
办法,在 findCandidateAdvisors()
办法中会再调用 BeanFactoryAspectJAdvisorsBuilder
的buildAspectJAdvisors()
办法来遍历以后容器中的每个由 @Aspect
注解润饰的切面,而后将每个切面的告诉封装成 Advisor
并返回,同时每遍历一个切面,都会将这个切面的所有 Advisor
缓存,以便下次获取时间接从缓存获取。
findEligibleAdvisors()
办法中在获取到以后容器中的所有 Advisor
后,会再调用 findAdvisorsThatCanApply()
办法来找出可能作用于以后 bean 的Advisor
,判断根据就是依据 Advisor
中的 Pointcut
来判断。
findEligibleAdvisors()
办法最初还会对作用于以后 bean 的所有 Advisor
进行排序,这个前面再剖析。所以 findEligibleAdvisors()
办法执行完,就获取到了可能作用于以后 bean 的所有告诉对应的Advisor
,也就获取到了告诉链。
最初再剖析一下 AnnotationAwareAspectJAutoProxyCreator
的findCandidateAdvisors()
办法中是如何获取容器中所有告诉以及是如何将每个告诉封装成 Advisor
的。BeanFactoryAspectJAdvisorsBuilder
的 buildAspectJAdvisors()
办法如下所示。
public List<Advisor> buildAspectJAdvisors() {
List<String> aspectNames = this.aspectBeanNames;
//aspectNames 不为 null 示意获取过切面 bean 的告诉并把这些告诉进行了缓存,那么间接从缓存获取告诉
if (aspectNames == null) {synchronized (this) {
aspectNames = this.aspectBeanNames;
if (aspectNames == null) {List<Advisor> advisors = new ArrayList<>();
aspectNames = new ArrayList<>();
// 把容器中的 bean 的名字获取进去
String[] beanNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(this.beanFactory, Object.class, true, false);
// 遍历每个 bean
for (String beanName : beanNames) {if (!isEligibleBean(beanName)) {continue;}
Class<?> beanType = this.beanFactory.getType(beanName, false);
if (beanType == null) {continue;}
// 判断 bean 是否是切面 bean
if (this.advisorFactory.isAspect(beanType)) {
// 把切面 bean 的名字增加到汇合中,以便后续缓存起来
aspectNames.add(beanName);
AspectMetadata amd = new AspectMetadata(beanType, beanName);
if (amd.getAjType().getPerClause().getKind() == PerClauseKind.SINGLETON) {
MetadataAwareAspectInstanceFactory factory =
new BeanFactoryAspectInstanceFactory(this.beanFactory, beanName);
// 调用到 ReflectiveAspectJAdvisorFactory 的 getAdvisors()办法来获取切面 bean 里的告诉
List<Advisor> classAdvisors = this.advisorFactory.getAdvisors(factory);
if (this.beanFactory.isSingleton(beanName)) {
// 如果切面 bean 是单例,则缓存切面 bean 的告诉
this.advisorsCache.put(beanName, classAdvisors);
}
else {
// 如果切面 bean 不是单例,则缓存切面 bean 的工厂
// 通过切面 bean 的工厂能够每次都生成切面 bean 的告诉
this.aspectFactoryCache.put(beanName, factory);
}
advisors.addAll(classAdvisors);
}
else {if (this.beanFactory.isSingleton(beanName)) {
throw new IllegalArgumentException("Bean with name'" + beanName +
"'is a singleton, but aspect instantiation model is not singleton");
}
MetadataAwareAspectInstanceFactory factory =
new PrototypeAspectInstanceFactory(this.beanFactory, beanName);
this.aspectFactoryCache.put(beanName, factory);
advisors.addAll(this.advisorFactory.getAdvisors(factory));
}
}
}
this.aspectBeanNames = aspectNames;
// 返回容器中的所有告诉
return advisors;
}
}
}
// 执行到这里示意曾经生成过告诉并进行了缓存
if (aspectNames.isEmpty()) {return Collections.emptyList();
}
List<Advisor> advisors = new ArrayList<>();
for (String aspectName : aspectNames) {
// 将每个切面 bean 的告诉从缓存中获取进去并加到后果汇合中
List<Advisor> cachedAdvisors = this.advisorsCache.get(aspectName);
if (cachedAdvisors != null) {advisors.addAll(cachedAdvisors);
}
else {
// 非单例切面 bean 就应用其对应的工厂新生成告诉,而后也退出到后果汇合中
MetadataAwareAspectInstanceFactory factory = this.aspectFactoryCache.get(aspectName);
advisors.addAll(this.advisorFactory.getAdvisors(factory));
}
}
// 返回容器中的所有告诉
return advisors;
}
下面 buildAspectJAdvisors()
办法中次要是 Spring 对切面 bean 的告诉的一个缓存策略,次要思维就是第一次获取时会实在的将所有切面 bean 的告诉获取进去并生成 Advisor
,而后缓存起来,后续再获取告诉时就从缓存中获取。上面持续深入分析一下切面bean 的告诉是如何被封装成 Advisor
的,理论的逻辑产生在 ReflectiveAspectJAdvisorFactory
的getAdvisors()
办法中,如下所示。
public List<Advisor> getAdvisors(MetadataAwareAspectInstanceFactory aspectInstanceFactory) {
// 失去切面 bean 的 Class 对象
Class<?> aspectClass = aspectInstanceFactory.getAspectMetadata().getAspectClass();
// 失去切面 bean 的名字
String aspectName = aspectInstanceFactory.getAspectMetadata().getAspectName();
validate(aspectClass);
MetadataAwareAspectInstanceFactory lazySingletonAspectInstanceFactory =
new LazySingletonAspectInstanceFactoryDecorator(aspectInstanceFactory);
List<Advisor> advisors = new ArrayList<>();
// 调用 getAdvisorMethods()办法来把非切点办法获取进去,并遍历
for (Method method : getAdvisorMethods(aspectClass)) {
// 先将告诉上的切点结构成 AspectJExpressionPointcut,而后再创立告诉对应的 Advisor
// 创立进去的 Advisor 理论为 InstantiationModelAwarePointcutAdvisorImpl
Advisor advisor = getAdvisor(method, lazySingletonAspectInstanceFactory, 0, aspectName);
// 以后 method 如果是告诉办法,则将告诉办法对应的 Advisor 增加到后果汇合中
// 如果不是告诉办法,失去的 Advisor 会为 null,就不会增加到后果汇合中
if (advisor != null) {advisors.add(advisor);
}
}
if (!advisors.isEmpty() && lazySingletonAspectInstanceFactory.getAspectMetadata().isLazilyInstantiated()) {Advisor instantiationAdvisor = new SyntheticInstantiationAdvisor(lazySingletonAspectInstanceFactory);
advisors.add(0, instantiationAdvisor);
}
for (Field field : aspectClass.getDeclaredFields()) {Advisor advisor = getDeclareParentsAdvisor(field);
if (advisor != null) {advisors.add(advisor);
}
}
return advisors;
}
至此获取告诉链的源码剖析结束。上面对获取作用于某个 bean 的告诉链步骤进行大节。
- 如果是第一次获取告诉链,那么会遍历容器中每个由
@Aspect
注解润饰的切面 bean 而后将其告诉封装成Advisor
并缓存起来,如果不是第一次获取,就间接从缓存中将所有Advisor
获取进去; - 而后筛选失去作用于以后 bean 的
Advisor
,并退出汇合中; - 返回筛选失去的汇合,作为后续创立 AOP 动静代理对象的告诉链。
五. AOP 动静代理对象的创立
已知在 AbstractAutoProxyCreator
的wrapIfNecessary()
办法中会先调用 getAdvicesAndAdvisorsForBean()
办法获取作用于以后 bean 的告诉链,那么下一步就应该基于告诉链为以后 bean 生成 AOP 动静代理对象,生成动静代理对象的逻辑在 AbstractAutoProxyCreator
的createProxy()
办法中,如下所示。
protected Object createProxy(Class<?> beanClass, @Nullable String beanName,
@Nullable Object[] specificInterceptors, TargetSource targetSource) {if (this.beanFactory instanceof ConfigurableListableBeanFactory) {AutoProxyUtils.exposeTargetClass((ConfigurableListableBeanFactory) this.beanFactory, beanName, beanClass);
}
// 创立 ProxyFactory 来创立动静代理对象
ProxyFactory proxyFactory = new ProxyFactory();
proxyFactory.copyFrom(this);
if (!proxyFactory.isProxyTargetClass()) {if (shouldProxyTargetClass(beanClass, beanName)) {proxyFactory.setProxyTargetClass(true);
}
else {evaluateProxyInterfaces(beanClass, proxyFactory);
}
}
Advisor[] advisors = buildAdvisors(beanName, specificInterceptors);
// 为 ProxyFactory 设置告诉链
proxyFactory.addAdvisors(advisors);
// 为 ProxyFactory 设置指标对象
proxyFactory.setTargetSource(targetSource);
customizeProxyFactory(proxyFactory);
proxyFactory.setFrozen(this.freezeProxy);
if (advisorsPreFiltered()) {proxyFactory.setPreFiltered(true);
}
// 调用 ProxyFactory 的 getProxy()办法创立动静代理对象
return proxyFactory.getProxy(getProxyClassLoader());
}
在 createProxy()
办法中会先创立一个 ProxyFactory
工厂,而后为 ProxyFactory
工厂设置告诉链和指标对象,后续的动静代理对象的创立就是由 ProxyFactory
工厂来实现。ProxyFactory
工厂类图如下所示。
所以 ProxyFactory
其实是一个 AdvisedSupport
。ProxyFactory
的getProxy()
办法如下所示。
public Object getProxy(@Nullable ClassLoader classLoader) {return createAopProxy().getProxy(classLoader);
}
在 ProxyFactory
的getProxy()
办法中会先调用到其父类 ProxyCreatorSupport
中的 createAopProxy()
办法,createAopProxy()
办法会有两种返回值,一个是 JdkDynamicAopProxy
,负责JDK 动静代理对象的生成,另一个是 CglibAopProxy
,负责CGLIB 动静代理对象的生成,上面看一下 ProxyCreatorSupport
的createAopProxy()
办法的实现。
protected final synchronized AopProxy createAopProxy() {if (!this.active) {activate();
}
//getAopProxyFactory()会返回一个 AopProxyFactory
//AopProxyFactory 的 createAopProxy()会返回一个 AopProxy
// 依据不同的指标类和不同的配置,会最终决定 AopProxy 是 JdkDynamicAopProxy 还是 CglibAopProxy
// 创立 AopProxy 时还会将 ProxyFactory 本人传入,所以创立进去的 AopProxy 也就持有了告诉链和指标对象
return getAopProxyFactory().createAopProxy(this);
}
ProxyCreatorSupport
的 createAopProxy()
办法中创立 AopProxy
时会将 ProxyFactory
传入,所以创立进去的 AopProxy
也就通过 ProxyFactory
持有了告诉链和指标对象。当初回到 ProxyFactory
的getProxy()
办法,在拿到 JdkDynamicAopProxy
或者 CglibAopProxy
之后,就会调用其 getProxy()
办法来生成动静代理对象,上面以 JdkDynamicAopProxy
的getProxy()
办法为例进行阐明,JdkDynamicAopProxy
的 getProxy()
办法如下所示。
public Object getProxy(@Nullable ClassLoader classLoader) {if (logger.isTraceEnabled()) {logger.trace("Creating JDK dynamic proxy:" + this.advised.getTargetSource());
}
// 调用 Proxy 的 newProxyInstance()办法来生成动静代理对象
//proxiedInterfaces 中有 bean 实现的接口
//JdkDynamicAopProxy 本身是实现了 InvocationHandler 接口,所以这将 JdkDynamicAopProxy 传到了 newProxyInstance()办法中
return Proxy.newProxyInstance(classLoader, this.proxiedInterfaces, this);
}
JdkDynamicAopProxy
的 getProxy()
办法就是调用 Proxy
的newProxyInstance()
办法来创立 JDK 动静代理对象。
至此 SpringAOP 中创立 AOP 动静代理对象的源码剖析结束。上面给出为 bean 基于告诉链创立动静代理对象的步骤大节。
- 创立
ProxyFactory
,为ProxyFactory
设置告诉链和指标对象,后续通过ProxyFactory
创立动静代理对象; - 通过
ProxyFactory
先创立AopProxy
,依据应用的动静代理形式的不同,创立进去的AopProxy
能够为JdkDynamicAopProxy
或者ObjenesisCglibAopProxy
,并且ProxyFactory
在创立AopProxy
时传入了本身,所以创立进去的AopProxy
也就持有了告诉链和指标对象; - 通过创立进去的
AopProxy
生成动静代理对象。
总结
Spring中有用户自定义的切面以及 Spring 框架提供的切面,这些切面会在 bean 的生命周期调用到 BeanPostProcessors
的postProcessAfterInitialization()
办法时织入 bean,织入的模式就是为bean 生成 AOP 动静代理对象。为 bean 生成动静代理对象前会先获取到容器中所有可能作用于这个 bean 的告诉,这些告诉会被封装成 Advisor
的实现类并退出到汇合中,能够称这个 Advisor
的汇合为告诉链,获取到告诉链后,会创立一个 ProxyFactory
工厂来帮忙创立动静代理对象,创立前会先通过 ProxyFactory
创立 AopProxy
,依据应用的动静代理形式的不同,创立进去的AopProxy
能够为 JdkDynamicAopProxy
或者 ObjenesisCglibAopProxy
,并且ProxyFactory
在创立 AopProxy
时传入了本身,所以创立进去的 AopProxy
也就持有了告诉链和指标对象,最初就是通过 AopProxy
将理论的动静代理对象生成进去。