死磕Spring之AOP篇 - Spring AOP自动代理(一)入口
该系列文章是本人在学习 Spring 的过程中总结下来的,里面涉及到相关源码,可能对读者不太友好,请结合我的源码注释 Spring 源码分析 GitHub 地址 进行阅读。
Spring 版本:5.1.14.RELEASE
在开始阅读 Spring AOP 源码之前,需要对 Spring IoC 有一定的了解,可查看我的 《死磕Spring之IoC篇 - 文章导读》 这一系列文章
了解 AOP 相关术语,可先查看 《Spring AOP 常见面试题) 》 这篇文章
该系列其他文章请查看:《死磕 Spring 之 AOP 篇 - 文章导读》
通过上一篇文章《Spring AOP 总览》我们对 Spring AOP 有了一个整体的认识,那么从本篇文章开始,我们一起来看看 Spring AOP 和 Spring IoC 是如何整合的,自动代理的过程做了哪些事情?
首先我们得清楚 Bean 的加载过程,整个过程中会调用相应的 BeanPostProcessor 对正在创建 Bean 进行处理,例如:
-
在 Bean 的实例化前,会调用
InstantiationAwareBeanPostProcessor#postProcessBeforeInstantiation(..)
方法进行处理 -
在 Bean 出现循环依赖的情况下,会调用
SmartInstantiationAwareBeanPostProcessor#getEarlyBeanReference(..)
方法对提前暴露的 Bean 进行处理 -
在 Bean 初始化后,会调用
BeanPostProcessor#postProcessAfterInitialization(..)
方法对初始化好的 Bean 进行处理
Spring AOP 则是通过上面三个切入点进行创建代理对象,实现自动代理。
- 在 Spring AOP 中主要是通过第
3
种 BeanPostProcessor 创建代理对象,在 Bean 初始化后,也就是一个“成熟态”,然后再尝试是否创建一个代理对象; - 第
2
种方式是为了解决 Bean 循环依赖的问题,虽然 Bean 仅实例化还未初始化,但是出现了循环依赖,不得不在此时创建一个代理对象; - 第
1
种方式是在 Bean 还没有实例化的时候就提前创建一个代理对象(创建了则不会继续后续的 Bean 的创建过程),例如 RPC 远程调用的实现,因为本地类没有远程能力,可以通过这种方式进行拦截。
对于 Bean 的加载过程不清楚的小伙伴可以查看我的《死磕Spring之IoC篇 - 文章导读》这篇文章,或者直接查看《死磕Spring之IoC篇 - Bean 的创建过程》 这篇文章
Spring AOP 自动代理的实现主要由 AbstractAutoProxyCreator
完成,它实现了 BeanPostProcessor、SmartInstantiationAwareBeanPostProcessor 和 InstantiationAwareBeanPostProcessor 三个接口,那么这个类就是 Spring AOP 的入口,在这里将 Advice 织入我们的 Bean 中,创建代理对象。
如何激活 AOP 模块?
如何开启 Spring 的 AOP 模块,首先我们需要引入 spring-aop
和 aspectjweaver
两个模块,然后通过下面的方式开启 AOP:
- 添加
@EnableAspectJAutoProxy
注解 - 添加
<aop:aspectj-autoproxy />
XML 配置
备注:在 Spring Boot 中使用 AOP 可以不需要上面两种配置,因为在 Spring Boot 中当你引入上面两个模块后,默认开启,可以看到下面这个配置类:
package org.springframework.boot.autoconfigure.aop;
@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 {}
}
只要存在 EnableAspectJAutoProxy
、Aspect
、Advice
、AnnotatedElement
四个 Class 对象,且 spring.aop.auto
配置为 true
(没有配置则为 true
),那么就会加载 AopAutoConfiguration 当前这个 Bean,而内部又使用了 @EnableAspectJAutoProxy
注解,那么表示开启 AOP。
至于这个注解或者 XML 配置的方式为什么就开启 AOP,是因为会引入 AbstractAutoProxyCreator
这个对象,具体怎么引入的,在后续文章进行分析😈
类图
简单描述:
- 【重点】
org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator
:AOP 自动代理的抽象类,完成主要的逻辑实现,提供一些骨架方法交由子类完成 org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator
:仅支持指定List<String> beanNames
完成自动代理,需要指定interceptorNames
拦截器- 【重点】
org.springframework.aop.framework.autoproxy.AbstractAdvisorAutoProxyCreator
:支持从当前 Spring 上下文获取所有 Advisor 对象,存在能应用与 Bean 的 Advisor 则创建代理对象 org.springframework.aop.framework.autoproxy.InfrastructureAdvisorAutoProxyCreator
:仅支持获取 Spring 内部的 Advisor 对象(BeanDefinition 的角色为 ROLE_INFRASTRUCTURE)org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator
:支持配置前缀,只能获取名称已该前缀开头的 Advisor 对象- 【重点】
org.springframework.aop.aspectj.autoproxy.AspectJAwareAdvisorAutoProxyCreator
:支持按照 AspectJ 的方式对 Advisor 进行排序 - 【重点】
org.springframework.aop.aspectj.annotation.AnnotationAwareAspectJAutoProxyCreator
:支持从带有@AspectJ
注解 Bean 中解析 Advisor 对象
我们主要关注上面【重点】的几个对象,因为 Sping AOP 推荐使用 AspectJ 里面的注解进行 AOP 的配置,你牢牢记住AbstractAutoProxyCreator这个自动代理类。
AbstractAutoProxyCreator
org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator
:AOP 自动代理的抽象类,完成主要的逻辑实现,提供一些骨架方法交由子类完成
相关属性
public abstract class AbstractAutoProxyCreator extends ProxyProcessorSupport
implements SmartInstantiationAwareBeanPostProcessor, BeanFactoryAware {
/** 空对象,表示不需要进行代理 */
@Nullable
protected static final Object[] DO_NOT_PROXY = null;
/**
* 空的数组,表示需要进行代理,但是没有解析出 Advice
* 查看 {@link BeanNameAutoProxyCreator#getAdvicesAndAdvisorsForBean} 就知道其用途
*/
protected static final Object[] PROXY_WITHOUT_ADDITIONAL_INTERCEPTORS = new Object[0];
/** DefaultAdvisorAdapterRegistry 单例,Advisor适配器注册中心 */
private AdvisorAdapterRegistry advisorAdapterRegistry = GlobalAdvisorAdapterRegistry.getInstance();
/** 是否冻结代理对象 */
private boolean freezeProxy = false;
/** 公共的拦截器对象 */
private String[] interceptorNames = new String[0];
/** 是否将 `interceptorNames` 拦截器放在最前面 */
private boolean applyCommonInterceptorsFirst = true;
/** 自定义的 TargetSource 创建器 */
@Nullable
private TargetSourceCreator[] customTargetSourceCreators;
@Nullable
private BeanFactory beanFactory;
/**
* 保存自定义 {@link TargetSource} 对象的 Bean 的名称
*/
private final Set<String> targetSourcedBeans = Collections.newSetFromMap(new ConcurrentHashMap<>(16));
/**
* 保存提前创建代理对象的 Bean
* key:cacheKey(Bean 的名称或者 Class 对象)
* value:Bean 对象
*
* Spring AOP 的设计之初是让 Bean 在完全创建好后才完成 AOP 代理,如果出现了循环依赖,则需要提前(实例化后还未初始化)创建代理对象
* 那么需要先保存提前创建代理对象的 Bean,这样在后面可以防止再次创建代理对象
*/
private final Map<Object, Object> earlyProxyReferences = new ConcurrentHashMap<>(16);
/**
* 保存代理对象的 Class 对象
* key:cacheKey(Bean 的名称或者 Class 对象)
* value:代理对象的 Class 对象(目标类的子类)
*
*/
private final Map<Object, Class<?>> proxyTypes = new ConcurrentHashMap<>(16);
/**
* 保存是否需要创建代理对象的信息
* key:cacheKey(Bean 的名称或者 Class 对象)
* value:是否需要创建代理对象,false 表示不需要创建代理对象,true 表示已创建代理对象
*/
private final Map<Object, Boolean> advisedBeans = new ConcurrentHashMap<>(256);
}
上面的每个属性都已经注释,先简单理解即可,具体在后面的方法可查看其用途
getEarlyBeanReference 方法
getEarlyBeanReference(Object bean, String beanName)
,用于处理早期暴露的对象,如果有必要的话会创建一个代理对象,该方法定义在 SmartInstantiationAwareBeanPostProcessor 中,实现如下:
/**
* 该方法对早期对象(提前暴露的对象,已实例化还未初始化)进行处理
* 参考 {@link org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#getEarlyBeanReference }
*
* @param bean the raw bean instance
* @param beanName the name of the bean
* @return 早期对象(可能是一个代理对象)
*/
@Override
public Object getEarlyBeanReference(Object bean, String beanName) {
// <1> 获取这个 Bean 的缓存 Key,默认为 Bean 的名称,没有则取其对应的 Class 对象
Object cacheKey = getCacheKey(bean.getClass(), beanName);
/*
* <2> 将当前 Bean 保存至 earlyProxyReferences 集合(早期的代理应用对象)
* 也就是说当这个 Bean 出现循环依赖了,在实例化后就创建了代理对象(如果有必要)
*/
this.earlyProxyReferences.put(cacheKey, bean);
// <3> 为这个 Bean 创建代理对象(如果有必要的话)
return wrapIfNecessary(bean, beanName, cacheKey);
}
该方法的处理过程如下:
- 获取这个 Bean 的缓存 Key,默认为 Bean 的名称,没有则取其对应的 Class 对象
- 将当前 Bean 保存至
earlyProxyReferences
集合(早期的代理应用对象),也就是说当这个 Bean 出现循环依赖了,在实例化后就创建了代理对象(如果有必要),可以防止后续初始化后再次创建代理对象 - 【重点】调用
wrapIfNecessary(..)
方法,为这个 Bean 创建代理对象(如果有必要的话),该方法在后面分析👨🎓
对于 getEarlyBeanReference(..)
方法在哪被调用,可能你已经忘记了,这里来回顾一下:
// 在 AbstractAutowireCapableBeanFactory#doCreateBean 创建 Bean 的过程中,实例化后会执行下面步骤
/**
* <3.2>
* 创建一个 ObjectFactory 实现类,用于返回当前正在被创建的 `bean`,提前暴露,保存在 `singletonFactories` (**三级 Map**)缓存中
*
* 可以回到前面的 {@link AbstractBeanFactory#doGetBean#getSingleton(String)} 方法
* 加载 Bean 的过程会先从缓存中获取单例 Bean,可以避免单例模式 Bean 循环依赖注入的问题
*/
addSingletonFactory(beanName,
// ObjectFactory 实现类
() -> getEarlyBeanReference(beanName, mbd, bean));
// 获取早期暴露的对象时候的处理,会调用 SmartInstantiationAwareBeanPostProcessor#getEarlyBeanReference(..) 方法
protected Object getEarlyBeanReference(String beanName, RootBeanDefinition mbd, Object bean) {
Object exposedObject = bean;
if (!mbd.isSynthetic() // RootBeanDefinition 不是用户定义的(由 Spring 解析出来的)
&& hasInstantiationAwareBeanPostProcessors()) {
for (BeanPostProcessor bp : getBeanPostProcessors()) {
if (bp instanceof SmartInstantiationAwareBeanPostProcessor) {
SmartInstantiationAwareBeanPostProcessor ibp = (SmartInstantiationAwareBeanPostProcessor) bp;
exposedObject = ibp.getEarlyBeanReference(exposedObject, beanName);
}
}
}
return exposedObject;
}
上面这个过程是为了处理循环依赖的问题,在 Bean 实例化后就提前暴露这个对象,如果真的出现了循环依赖,如果这个 Bean 需要进行代理,那么就不得不提前为它创建一个代理对象,虽然这个 Bean 还未初始化,不是一个“成熟态”。
关于 Spring 如何处理循环依赖的过程,如果你不熟悉可查看我的另一篇文章《死磕Spring之IoC篇 - 单例 Bean 的循环依赖处理》
postProcessBeforeInstantiation 方法
postProcessBeforeInstantiation(Class<?> beanClass, String beanName)
,Bean 的创建过程中实例化前置处理,也就是允许你在创建 Bean 之前进行处理。如果该方法返回的不为 null
,后续 Bean 加载过程不会继续,也就是说这个方法可用于获取一个 Bean 对象。通常这里用于创建 AOP 代理对象,或者 RPC 远程调用的实现(因为本地类没有远程能力,可以通过这种方式进行拦截)。
该方法定义在 InstantiationAwareBeanPostProcessor 中,实现如下:
/**
* 在加载 Bean 的过程中,Bean 实例化的前置处理
* 如果返回的不是 null 则不会进行后续的加载过程,也就是说这个方法用于获取一个 Bean 对象
* 通常这里用于创建 AOP 代理对象,返回的对象不为 null,则会继续调用下面的 {@link this#postProcessAfterInitialization} 方法进行初始化后置处理
* 参考 {@link org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#resolveBeforeInstantiation}
*
* @param beanClass the class of the bean to be instantiated
* @param beanName the name of the bean
* @return 代理对象或者空对象
*/
@Override
public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) {
// <1> 获取这个 Bean 的缓存 Key,默认为 Bean 的名称,没有则取其对应的 Class 对象
Object cacheKey = getCacheKey(beanClass, beanName);
// <2> 如果没有 beanName 或者没有自定义生成 TargetSource
if (!StringUtils.hasLength(beanName) // 没有 beanName
|| !this.targetSourcedBeans.contains(beanName)) // 没有自定义生成 TargetSource
{
/*
* <2.1> 已创建代理对象(或不需要创建),则直接返回 null,进行后续的 Bean 加载过程
*/
if (this.advisedBeans.containsKey(cacheKey)) {
return null;
}
/*
* <2.2>不需要创建代理对象,则直接返回 null,进行后续的 Bean 加载过程
*/
if (isInfrastructureClass(beanClass) // 如果是 Spring 内部的 Bean(Advice、Pointcut、Advisor 或者 AopInfrastructureBean 标记接口)
|| shouldSkip(beanClass, beanName)) // 应该跳过
{
// 将这个 Bean 不需要创建代理对象的结果保存起来
this.advisedBeans.put(cacheKey, Boolean.FALSE);
return null;
}
}
/*
* <3> 通过自定义 TargetSourceCreator 创建自定义 TargetSource 对象
* 默认没有 TargetSourceCreator,所以这里通常都是返回 null
*/
TargetSource targetSource = getCustomTargetSource(beanClass, beanName);
/*
* <4> 如果 TargetSource 不为空,表示需要创建代理对象
*/
if (targetSource != null) {
if (StringUtils.hasLength(beanName)) {
// <4.1> 将当前 beanName 保存至集合,表示这个 Bean 已自定义生成 TargetSource 对象
this.targetSourcedBeans.add(beanName);
}
// <4.2> 获取能够应用到当前 Bean 的所有 Advisor(已根据 @Order 排序)
Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(beanClass, beanName, targetSource);
// <4.3> 创建代理对象,JDK 动态代理或者 CGLIB 动态代理
Object proxy = createProxy(beanClass, beanName, specificInterceptors, targetSource);
// <4.4> 将代理对象的 Class 对象(目标类的子类)保存
this.proxyTypes.put(cacheKey, proxy.getClass());
// <4.5> 返回代理对象
return proxy;
}
// <5> 否则,直接返回 null,进行后续的 Bean 加载过程
return null;
}
该方法的处理过程如下:
-
获取这个 Bean 的缓存 Key,默认为 Bean 的名称,没有则取其对应的 Class 对象
-
如果没有
beanName
或者没有自定义生成 TargetSource- 已创建代理对象(或不需要创建),则直接返回
null
,进行后续的 Bean 加载过程 - 满足下面其中一个条件表示不需要创建代理对象,则直接返回
null
,并将这个 Bean 不需要创建代理对象的结果保存至advisedBeans
中- 如果是 Spring 内部的 Bean(Advice、Pointcut、Advisor 或者 AopInfrastructureBean 标记接口)
- 应该跳过
- 已创建代理对象(或不需要创建),则直接返回
-
通过自定义 TargetSourceCreator 创建自定义 TargetSource 对象,默认没有 TargetSourceCreator,所以这里通常都是返回
null
@Nullable protected TargetSource getCustomTargetSource(Class<?> beanClass, String beanName) { if (this.customTargetSourceCreators != null && this.beanFactory != null && this.beanFactory.containsBean(beanName)) { for (TargetSourceCreator tsc : this.customTargetSourceCreators) { // 通过 TargetSourceCreator 获取 `beanName` 的自定义 TargetSource TargetSource ts = tsc.getTargetSource(beanClass, beanName); if (ts != null) { return ts; } } } return null; }
-
如果 TargetSource 不为空,表示需要创建代理对象
- 将当前
beanName
保存至targetSourcedBeans
集合,表示这个 Bean 已自定义生成 TargetSource 对象 - 调用
getAdvicesAndAdvisorsForBean(..)
方法,获取能够应用到当前 Bean 的所有 Advisor(已根据 @Order 排序),在后面进行分析👨🎓 - 调用
createProxy(..)
方法,创建代理对象,JDK 动态代理或者 CGLIB 动态代理,在后面进行分析👨🎓 - 将代理对象的 Class 对象(目标类的子类)保存至
proxyTypes
- 返回代理对象
- 将当前
-
否则,直接返回
null
,进行后续的 Bean 加载过程
这里先解释一下 TargetSource,这个对象表示目标类的来源,用于获取代理对象的目标对象,上面如果存在 TargetSourceCreator,表示可以创建自定义的 TargetSource,也就需要进行 AOP 代理。默认情况下是没有 TargetSourceCreator 的,具体使用场景目前还没有接触过。
上面的 4.2
和 4.3
两个方法非常复杂,放在后面进行分析😈
同样对于 postProcessBeforeInstantiation(..)
方法在哪被调用,可能你已经忘记了,这里来回顾一下:
// 在 AbstractAutowireCapableBeanFactory#createBean 创建 Bean 的过程中,开始前会执行下面步骤
/**
* <3> 在实例化前进行相关处理,会先调用所有 {@link InstantiationAwareBeanPostProcessor#postProcessBeforeInstantiation}
* 注意,如果这里返回对象不是 `null` 的话,不会继续往下执行原本初始化操作,直接返回,也就是说这个方法返回的是最终实例对象
* 可以通过这种方式提前返回一个代理对象,例如 AOP 的实现,或者 RPC 远程调用的实现(因为本地类没有远程能力,可以通过这种方式进行拦截)
*/
Object bean = resolveBeforeInstantiation(beanName, mbdToUse);
if (bean != null) {
return bean;
}
protected Object resolveBeforeInstantiation(String beanName, RootBeanDefinition mbd) {
Object bean = null;
if (!Boolean.FALSE.equals(mbd.beforeInstantiationResolved)) {
// Make sure bean class is actually resolved at this point.
// 如果 RootBeanDefinition 不是用户定义的(由 Spring 解析出来的),并且存在 InstantiationAwareBeanPostProcessor 处理器
if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
Class<?> targetType = determineTargetType(beanName, mbd);
if (targetType != null) {
// 实例化前置处理
bean = applyBeanPostProcessorsBeforeInstantiation(targetType, beanName);
if (bean != null) {
// 后置处理
bean = applyBeanPostProcessorsAfterInitialization(bean, beanName);
}
}
}
mbd.beforeInstantiationResolved = (bean != null);
}
return bean;
}
上面过程是提供一种扩展点,可以让你在 Bean 创建之前进行相关处理,例如进行 AOP 代理,或者 RPC 远程调用的实现(因为本地类没有远程能力,可以通过这种方式进行拦截)。
关于 Spring Bean 的创建过程,如果你不熟悉可查看我的另一篇文章《死磕Spring之IoC篇 - Bean 的创建过程》
postProcessAfterInitialization 方法
postProcessAfterInitialization(@Nullable Object bean, String beanName)
,Bean 的初始化后置处理,在 Bean 初始化后,已经进入一个“成熟态”,那么此时就可以创建 AOP 代理对象了,如果有必要的话。
该方法定义在 BeanPostProcessor 中,实现如下:
/**
* 在加载 Bean 的过程中,Bean 初始化的后置处理
* 参考 {@link org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#initializeBean(String, Object, RootBeanDefinition)}
*/
@Override
public Object postProcessAfterInitialization(@Nullable Object bean, String beanName) {
// <1> 如果 bean 不为空则进行接下来的处理
if (bean != null) {
// <1.1> 获取这个 Bean 的缓存 Key,默认为 Bean 的名称,没有则取其对应的 Class 对象
Object cacheKey = getCacheKey(bean.getClass(), beanName);
/*
* <1.2> 移除 `earlyProxyReferences` 集合中保存的当前 Bean 对象(如果有的话)
* 如果 earlyProxyReferences 集合中没有当前 Bean 对象,表示在前面没有创建代理对象
*/
if (this.earlyProxyReferences.remove(cacheKey) != bean) {
// 这里尝试为这个 Bean 创建一个代理对象(如果有必要的话)
return wrapIfNecessary(bean, beanName, cacheKey);
}
}
// <2> 直接返回 bean 对象
return bean;
}
该方法的处理过程如下:
-
如果
bean
不为空则进行接下来的处理-
获取这个 Bean 的缓存 Key,默认为 Bean 的名称,没有则取其对应的 Class 对象
-
移除
earlyProxyReferences
集合中保存的当前 Bean 对象(如果有的话),如果earlyProxyReferences
集合中没有当前 Bean 对象,表示在前面没有创建代理对象【重点】那么调用
wrapIfNecessary(..)
方法,尝试为这个 Bean 创建一个代理对象(如果有必要的话),该方法在后面分析👨🎓
-
-
直接返回
bean
对象
对于 postProcessAfterInitialization(..)
方法在哪被调用,可能你已经忘记了,这里来回顾一下:
// 在 AbstractAutowireCapableBeanFactory#doCreateBean#initializeBean 创建 Bean 的过程中,属性填充后会进行初始化,初始化后会执行下面的操作
/**
* <4> **初始化**阶段的**后置处理**,执行所有 BeanPostProcessor 的 postProcessAfterInitialization 方法
*
* 在 {@link AbstractApplicationContext#prepareBeanFactory} 方法中会添加 {@link ApplicationListenerDetector} 处理器
* 如果是单例 Bean 且为 ApplicationListener 类型,则添加到 Spring 应用上下文,和 Spring 事件相关
*/
if (mbd == null || !mbd.isSynthetic()) {
wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
}
public Object applyBeanPostProcessorsAfterInitialization(Object existingBean, String beanName)
throws BeansException {
Object result = existingBean;
// 遍历所有 BeanPostProcessor
for (BeanPostProcessor processor : getBeanPostProcessors()) {
// 初始化的后置处理,返回 `current` 处理结果
Object current = processor.postProcessAfterInitialization(result, beanName);
// 处理结果为空,则直接返回 `result`
if (current == null) {
return result;
}
// 否则,`result` 复制 `current`
result = current;
}
return result;
}
上面这个过程在 Bean 初始化后,提供一个扩展点允许对这个 Bean 进行后置处理,此时 Bean 进入一个 “成熟态”,在这里则可以进行 AOP 代理对象的创建
关于 Spring Bean 的初始化过程,如果你不熟悉可查看我的另一篇文章《死磕Spring之IoC篇 - Bean 的创建过程》
wrapIfNecessary 方法
wrapIfNecessary(Object bean, String beanName, Object cacheKey)
,该方法用于创建 AOP 代理对象,如果有必要的话
上面的 getEarlyBeanReference(..)
和 postProcessAfterInitialization(..)
方法都会调用这个方法,如下:
protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {
/*
* <1> 如果当前 Bean 已经创建过自定义 TargetSource 对象
* 表示在上面的**实例化前置处理**中已经创建代理对象,那么直接返回这个对象
*/
if (StringUtils.hasLength(beanName)
&& this.targetSourcedBeans.contains(beanName))
{
return bean;
}
// <2> `advisedBeans` 保存了这个 Bean 没有必要创建代理对象,则直接返回
if (Boolean.FALSE.equals(this.advisedBeans.get(cacheKey))) {
return bean;
}
/*
* <3> 不需要创建代理对象,则直接返回当前 Bean
*/
if (isInfrastructureClass(bean.getClass()) // 如果是 Spring 内部的 Bean(Advice、Pointcut、Advisor 或者 AopInfrastructureBean 标记接口)
|| shouldSkip(bean.getClass(), beanName)) // 应该跳过
{
// 将这个 Bean 不需要创建代理对象的结果保存起来
this.advisedBeans.put(cacheKey, Boolean.FALSE);
return bean;
}
// Create proxy if we have advice.
// <4> 获取能够应用到当前 Bean 的所有 Advisor(已根据 @Order 排序)
Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null);
// <5> 如果有 Advisor,则进行下面的动态代理创建过程
if (specificInterceptors != DO_NOT_PROXY) {
// <5.1> 将这个 Bean 已创建代理对象的结果保存至 `advisedBeans`
this.advisedBeans.put(cacheKey, Boolean.TRUE);
// <5.2> 创建代理对象,JDK 动态代理或者 CGLIB 动态代理
// 这里传入的是 SingletonTargetSource 对象,可获取代理对象的目标对象(当前 Bean)
Object proxy = createProxy(bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource(bean));
// <5.3> 将代理对象的 Class 对象(目标类的子类)保存
this.proxyTypes.put(cacheKey, proxy.getClass());
// <5.4> 返回代理对象
return proxy;
}
// <6> 否则,将这个 Bean 不需要创建代理对象的结果保存起来
this.advisedBeans.put(cacheKey, Boolean.FALSE);
// <7> 返回这个 Bean 对象
return bean;
}
该方法处理过程如下:
-
如果当前 Bean 已经创建过自定义 TargetSource 对象,表示在上面的实例化前置处理中已经创建代理对象,那么直接返回这个对象
-
如果
advisedBeans
保存了这个 Bean 没有必要创建代理对象,则直接返回这个对象 -
如果满足下面其中一个条件,表示不需要创建代理对象,则直接返回当前 Bean,并将这个 Bean 不需要创建代理对象的结果保存至
advisedBeans
中- 如果是 Spring 内部的 Bean(Advice、Pointcut、Advisor 或者 AopInfrastructureBean 标记接
- 应该跳过
-
调用
getAdvicesAndAdvisorsForBean(..)
方法,获取能够应用到当前 Bean 的所有 Advisor(已根据 @Order 排序),在后面进行分析👨🎓 -
如果有 Advisor,则进行下面的动态代理创建过程
-
将这个 Bean 已创建代理对象的结果保存至
advisedBeans
-
调用
createProxy(..)
方法,创建代理对象,JDK 动态代理或者 CGLIB 动态代理,在后面进行分析👨🎓注意,这里传入的是 SingletonTargetSource 对象,可获取代理对象的目标对象(当前 Bean)
-
将代理对象的 Class 对象(目标类的子类)保存至
proxyTypes
-
返回代理对象
-
-
否则,将这个 Bean 不需要创建代理对象的结果保存至
advisedBeans
-
返回这个 Bean 对象
到这里,getEarlyBeanReference(..)
、postProcessBeforeInstantiation(..)
和 postProcessAfterInitialization(..)
三个方法的 AOP 自动代理过程主要分为两步:
-
调用
getAdvicesAndAdvisorsForBean(..)
方法,获取能够应用到当前 Bean 的所有 Advisor(已根据 @Order 排序) -
调用
createProxy(..)
方法,根据找到的 Advisor 创建一个代理对象,JDK 动态代理或者 CGLIB 动态代理
上面的流程看起来并不复杂,看着好像就调用两个方法,不过不要被表象所迷惑,这只是冰山一角。
总结
Spring AOP 自动代理是通过实现 Spring IoC 中的几种 BeanPostProcessor 处理器,在 Bean 的加载过程中进行扩展,如果有必要的话(找到了能够应用于这个 Bean 的 Advisor)则创建 AOP 代理对象, JDK 动态代理或者 CGLIB 动态代理。
AbstractAutoProxyCreator 则是自动代理的入口,实现了三种 BeanPostProcessor 处理器,SmartInstantiationAwareBeanPostProcessor、InstantiationAwareBeanPostProcessor 和 BeanPostProcessor,实现的三个方法:
-
getEarlyBeanReference(..)
:用于处理早期暴露的对象,如果有必要的话会创建一个代理对象 -
postProcessBeforeInstantiation(..)
:Bean 的创建过程中实例化前置处理,允许你在创建 Bean 之前进行处理。如果该方法返回的不为null
,后续 Bean 加载过程不会继续,也就是说这个方法可用于获取一个 Bean 对象。通常这里用于创建 AOP 代理对象,或者 RPC 远程调用的实现(因为本地类没有远程能力,可以通过这种方式进行拦截)。 -
postProcessAfterInitialization(..)
:Bean 的初始化后置处理,在 Bean 初始化后,已经进入一个“成熟态”,那么此时就可以创建 AOP 代理对象了,如果有必要的话。
详细过程参考上面的方法,我们主要是通过第 3
种方法创建代理对象,这三种方法的处理过程主要分为以下两步:
-
调用
getAdvicesAndAdvisorsForBean(..)
方法,筛选出合适的 Advisor 对象们 -
调用
createProxy(..)
方法,根据找到的 Advisor 创建一个代理对象,JDK 动态代理或者 CGLIB 动态代理
由于这两个步骤都比较复杂,考虑到文章的可读性,所以另起两篇文章分别分析