Spring 源码阅读 48:用于创建 AOP 代理的后处理器分析
基于 Spring Framework v5.2.6.RELEASE
概述
前面两篇文章分析了在注解配置和 XML 配置的情况下,Spring 是如何开启 AOP 特性的,经过源码分析我们知道,这两种方式的 AOP 开启,本质上都是注册了一个用来创建 AOP 代理的后处理器。
对于在 XML 中配置切面的情况,Spring 会把创建代理的工作交给 AspectJAwareAdvisorAutoProxyCreator 后处理器来处理,而对于通过注解配置切面的情况,则交由 AnnotationAwareAspectJAutoProxyCreator 后处理器处理。
在本文章,将对这两个后处理器进行分析,了解他们大致的工作原理。
继承关系
AspectJAwareAdvisorAutoProxyCreator 和 AnnotationAwareAspectJAutoProxyCreator 两个后处理器的继承关系,在前两篇文章中已经了解过了,这里我们再做简单的回顾。
从上图中可以知道,这两个类是直接继承的父子类,他们有很多共同继承的类和实现的接口,可以推测出他们的工作逻辑有很大一部分是相同的。
由于他们是作为后处理器注册到 Spring 容器中的,因此,他们完成 AOP 代理创建的逻辑,一定是在后处理器的方法中。从上图中看到,他们共实现了三个后处理器的接口,接下来,我们再看这三个接口中定义的方法。
实现接口
先看看这三个接口都定义了哪些方法。
既然后处理器的作用要生成一个代理对象,那么,我们就应该去分析后处理器中可以修改被处理的 Bean 对象的处理方法,再上图中罗列的方法中有以下这些:
postProcessBeforeInstantiation
方法可以在 Spring 实例化 Bean 对象之前,创建一个 Bean 对象。postProcessBeforeInitialization
方法可以在 Bean 的初始化方法被执行前,修改 Bean 对象。postProcessAfterInitialization
方法可以在 Bean 的初始化方法被执行前,修改 Bean 对象。
以上三个方法,都可能在执行的过程中,将当前的 Bean 对象,修改为新创建的代理对象。因此,接下来,我们需要从两个后处理器中找到这三个方法的实现逻辑。
不过,在源码中可以发现,这两个后处理器的后处理方法,都是在它们共同的父类 AbstractAutoProxyCreator 中实现的,所以,我们之后只需要分析 AbstractAutoProxyCreator 类中实现的处理方法就行了。并且,postProcessBeforeInitialization
方法的实现是一个没有任何处理逻辑的默认实现,我们接下来从postProcessBeforeInstantiation
和postProcessAfterInitialization
两个方法中分析自动创建代理的逻辑。
代理创建的原理
下面从 AbstractAutoProxyCreator 的源码中,找到这两个方法进行分析。
postProcessBeforeInstantiation
先看postProcessBeforeInstantiation
方法
@Override
public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) {
Object cacheKey = getCacheKey(beanClass, beanName);
if (!StringUtils.hasLength(beanName) || !this.targetSourcedBeans.contains(beanName)) {
if (this.advisedBeans.containsKey(cacheKey)) {
return null;
}
if (isInfrastructureClass(beanClass) || shouldSkip(beanClass, beanName)) {
this.advisedBeans.put(cacheKey, Boolean.FALSE);
return null;
}
}
// Create proxy here if we have a custom TargetSource.
// Suppresses unnecessary default instantiation of the target bean:
// The TargetSource will handle target instances in a custom fashion.
TargetSource targetSource = getCustomTargetSource(beanClass, beanName);
if (targetSource != null) {
if (StringUtils.hasLength(beanName)) {
this.targetSourcedBeans.add(beanName);
}
Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(beanClass, beanName, targetSource);
Object proxy = createProxy(beanClass, beanName, specificInterceptors, targetSource);
this.proxyTypes.put(cacheKey, proxy.getClass());
return proxy;
}
return null;
}
方法的核心是后半部分的if
语句块,在if语句块之前,通过getCustomTargetSource
获取了当前 Bean 对象的自定义 TargetSource。TargetSource 指的是,Spring 创建的代理在调用目标方法时候要查找的目标来源,在创建代理对象时,当前的 Bean 对象,会被封装成一个 TargetSource 交给代理类,用于找到被增强的对象本身。
通常情况下,我们不会自定义 TargetSource,因此,这个方法并不是我们要找的创建代理的地方。
postProcessAfterInitialization
接下来,找到postProcessAfterInitialization
方法。
@Override
public Object postProcessAfterInitialization(@Nullable Object bean, String beanName) {
if (bean != null) {
Object cacheKey = getCacheKey(bean.getClass(), beanName);
if (this.earlyProxyReferences.remove(cacheKey) != bean) {
return wrapIfNecessary(bean, beanName, cacheKey);
}
}
return bean;
}
这个方法是在 Bean 实例被执行初始化操作后被调用的,因此方法可以通过参数拿到 Bean 实例对象本身,以及 Bean 的名称。
首先,确保了 Bean 不为空之后,通过getCacheKey
方法获得了一个缓存 Key。这个方法在刚刚的postProcessBeforeInstantiation
方法中也见过,我们来看一下这个方法。
protected Object getCacheKey(Class<?> beanClass, @Nullable String beanName) {
if (StringUtils.hasLength(beanName)) {
return (FactoryBean.class.isAssignableFrom(beanClass) ?
BeanFactory.FACTORY_BEAN_PREFIX + beanName : beanName);
}
else {
return beanClass;
}
}
方法中判断了 Bean 的名称是否为空,如果不为空,则根据当前的 Bean 是不是一个 FactoryBean 来返回带或者不带工厂前缀的 Bean 名称,如果 Bean 的名称为空,则直接返回 Bean 得类型本身。
这个方法的目的是获得一个缓存 Key,用于 AbstractAutoProxyCreator 中的缓存容器。
回到postProcessAfterInitialization
方法中,接着,从earlyProxyReferences
集合中,移除当前 Bean 对象对应的缓存 Key 保存的内容。那这个集合中存放了什么呢?在 AbstractAutoProxyCreator 源码中,除了这里,只有一处操作了earlyProxyReferences
集合,而且是put
操作,在另外一个方法中。
@Override
public Object getEarlyBeanReference(Object bean, String beanName) {
Object cacheKey = getCacheKey(bean.getClass(), beanName);
this.earlyProxyReferences.put(cacheKey, bean);
return wrapIfNecessary(bean, beanName, cacheKey);
}
这其实也是一个后处理器方法,之所以在寻找创建代理逻辑的时候没有考虑这个方法,是因为这个方法是在获取早期 Bean 对象的时候被调用的,也就是说,它不一定会被调用,而且调用的时机也不确定。在方法中,通过缓存 Key 向earlyProxyReferences
集合中存放了早期的代理引用,方法最后返回了调用wrapIfNecessary
方法的结果,这个方法我们稍后介绍。
再次回到postProcessBeforeInstantiation
中,如果从earlyProxyReferences移除的内容,并不是 Bean 本身,则执行wrapIfNecessary
方法并将结果作为后处理方法的结果返回。
wrapIfNecessary 方法
到这里,我们就需要看wrapIfNecessary方法,从名字就可以看出,它的作用是在必要的时候,对 Bean 对象进行包装,并且包装好的结果会作为容器中 Bean 的对象。因此,这个方法就是用来创建 Bean 对象代理的方法。
// org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator#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;
}
// Create proxy if we have advice.
Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null);
if (specificInterceptors != DO_NOT_PROXY) {
this.advisedBeans.put(cacheKey, Boolean.TRUE);
Object proxy = createProxy(
bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource(bean));
this.proxyTypes.put(cacheKey, proxy.getClass());
return proxy;
}
this.advisedBeans.put(cacheKey, Boolean.FALSE);
return bean;
}
在判断了一些不需要在此处进行包装处理的情况后,进入了创建代理的逻辑,根据需不需要增强处理,返回创建好的代理对象,或者原本的 Bean 对象本身。
这部分逻辑,放到之后的文章来分析。
总结
本文分析了用于创建 AOP 代理对象的后处理器,主要是 AbstractAutoProxyCreator 类中的后处理方法。从它实现的后处理器接口中定义的方法中,找到了用于创建 AOP 代理的逻辑是在postProcessBeforeInstantiation方法中,也就是 AOP 代理是 Bean 执行完初始化逻辑之后创建的。
下一篇开始,将深入wrapIfNecessary
方法,分析代理对象创建的过程。
转载自:https://juejin.cn/post/7155645119922700319