前言
上一篇中我们扒拉了一下spring-aop
的底裤,详细解读了spring-aop
中的各种抽象概念,本篇开始我们一起研究研究spring-aop
的织入过程(基于5.2.6.RELEASE
)。建议各位同学本地打开一份源码对照食用,效果更佳。
前方高能!!!本篇重度依赖于上一篇解读的抽象概念,不熟悉的同学请速速撤离,以免误伤。
正式开始之前,各位同学还请思考一下,在拥有了关于AOP的全局视角之后,如果是你,会怎样有机地结合这些概念来实现织入呢?我听到有同学说利用BeanPostProcessor
。嗯,不错,Bean后置处理器给我们提供了这样一个切入点——可以在Bean自动装配完毕、行将可用之前对它进行定制,如果我们在这里返回一个代理对象,那么它就会取代原始对象。具体来说,就是在BeanPostProcessor#postProcessAfterInitialization(...)
回调中完成织入并返回新创建的代理对象。那么,真的是这样吗?
一切从EnableAspectJAutoProxy说起
EnableAspectJAutoProxy
的作用自不必多说,不过我们今天深入一点,探究一下它的源码。这个说白了就是看它通过Import
元注解向容器中导入了些什么,我们知道Spring中EnableXXX
类型的注解都是代理给Import
元注解向容器中导入功能组件的。
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import({AspectJAutoProxyRegistrar.class})
public @interface EnableAspectJAutoProxy {
/**
* 是基于JDK动态代理还是CGLIB
*/
boolean proxyTargetClass() default false;
/**
* 是否需要暴露代理对象到ThreadLocal中
*/
boolean exposeProxy() default false;
}
注意到注解中的两个属性也存在于Advised
接口,而Advised
又保存着AOP配置信息,因此我们可以大胆地猜测这两个属性值最终会同步给Advised
。
class AspectJAutoProxyRegistrar implements ImportBeanDefinitionRegistrar {
@Override
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata,
BeanDefinitionRegistry registry) {
// 向容器中导入一个类型为AnnotationAwareAspectJAutoProxyCreator的Bean
// 同时设置它的优先级为Ordered.HIGHEST_PRECEDENCE,角色为BeanDefinition.ROLE_INFRASTRUCTURE
AopConfigUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(registry);
// 提取EnableAspectJAutoProxy注解的属性
AnnotationAttributes enableAspectJAutoProxy =
AnnotationConfigUtils.attributesFor(importingClassMetadata, EnableAspectJAutoProxy.class);
if (enableAspectJAutoProxy != null) {
// 如果proxyTargetClass=true,同步给AnnotationAwareAspectJAutoProxyCreator
if (enableAspectJAutoProxy.getBoolean("proxyTargetClass")) {
AopConfigUtils.forceAutoProxyCreatorToUseClassProxying(registry);
}
// 如果exposeProxy=true,同步给AnnotationAwareAspectJAutoProxyCreator
if (enableAspectJAutoProxy.getBoolean("exposeProxy")) {
AopConfigUtils.forceAutoProxyCreatorToExposeProxy(registry);
}
}
}
}
AspectJAutoProxyRegistrar
做的事情非常简单:
- 向容器中导入一个
AnnotationAwareAspectJAutoProxyCreator
类型的Bean,并设置优先级和角色 - 同步
EnableAspectJAutoProxy
注解的属性值给它
那么问题来了,这个AnnotationAwareAspectJAutoProxyCreator
是个什么鬼呢?看名字的话它是某种自动代理的创建器,那么是不是就是它实现了BeanPostProcessor
接口呢?
Variant AutoProxyCreator
Hierarchy of AnnotationAwareAspectJAutoProxyCreator
aj-arch.png 查看类图,结果确如我们所想,AnnotationAwareAspectJAutoProxyCreator
实现了BeanPostProcessor
接口,只不过是其父类实现的。好呗,扒就扒到底,AbstractAutoProxyCreator
走起。
What is SmartInstantiationAwareBeanPostProcessor
题外话,AbstractAutoProxyCreator
实现的并不是普通的BeanPostProcessor
,而是SmartInstantiationAwareBeanPostProcessor
。有些同学可能不太熟悉这个接口,简单说明一下,我们先看它的父接口InstantiationAwareBeanPostProcessor
。
public interface InstantiationAwareBeanPostProcessor extends BeanPostProcessor {
/**
* 在Bean创建之前调用,如果返回一个非空对象,就会跳过标准的Spring Bean创建流程而直接来到
* postProcessAfterInitialization(...),具体逻辑可查看AbstractAutowireCapableBeanFactory#createBean(...)
* 也就是说,如果我们想自己全盘接管Bean的生命周期,就可以使用这个回调
*/
@Nullable
default Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) throws BeansException {
return null;
}
/**
* 是否需要为刚创建好的Bean执行自动注入等标准流程,true表示执行标准的Spring Bean初始化流程,
* false表示由用户自己控制初始化流程,具体逻辑可查看AbstractAutowireCapableBeanFactory#populateBean(...)
*/
default boolean postProcessAfterInstantiation(Object bean, String beanName) throws BeansException {
return true;
}
/**
* 在PropertyValues应用到目标Bean上之前,给用户一个机会去修改PropertyValues,这一步其实在
* BeanFactoryPostProcessor#postProcessBeanFactory(...)中也能实现,只是没有这里来得方便
*/
@Nullable
default PropertyValues postProcessProperties(PropertyValues pvs, Object bean,
String beanName) throws BeansException {
return null;
}
/**
* 已由#postProcessProperties(...)代替
*/
@Deprecated
@Nullable
default PropertyValues postProcessPropertyValues(PropertyValues pvs, PropertyDescriptor[] pds,
Object bean, String beanName) throws BeansException {
return pvs;
}
}
spring-context
中,CommonAnnotationBeanPostProcessor
就实现了InstantiationAwareBeanPostProcessor
接口用以支持javax.annotation.Resource
注解。接下来是SmartInstantiationAwareBeanPostProcessor
。
public interface SmartInstantiationAwareBeanPostProcessor extends InstantiationAwareBeanPostProcessor {
/**
* 预测#postProcessBeforeInstantiation(...)的回调参数beanClass,主要还是用来做type match
*/
@Nullable
default Class<?> predictBeanType(Class<?> beanClass, String beanName) throws BeansException {
return null;
}
/**
* 返回候选的构造函数,用来决定是否采用autowire by constructor这种装配策略,
* 具体逻辑可查看AbstractAutowireCapableBeanFactory#createBeanInstance(...)
*/
@Nullable
default Constructor<?>[] determineCandidateConstructors(Class<?> beanClass,
String beanName) throws BeansException {
return null;
}
/**
* Spring解决循环依赖的思路是提前创建 + 缓存,#getEarlyBeanReference(...)给了我们一个机
* 会去访问这个被提前创建的Bean,因此我们可以在这里提前创建代理对象被返回,具体逻辑可查看
* AbstractAutowireCapableBeanFactory#getEarlyBeanReference(...)
* NOTE: 因为循环依赖的关系,这里传递进来的Bean是没有完全初始化好的,换句话说客户端是不能直接使用的
*/
default Object getEarlyBeanReference(Object bean, String beanName) throws BeansException {
return bean;
}
}
AbstractAutoProxyCreator是如何执行织入的
Implementing SmartInstantiationAwareBeanPostProcessor
好了,言归正题,回到AbstractAutoProxyCreator
,挑出它对SmartInstantiationAwareBeanPostProcessor
的实现部分。
/**
* 换个角度理解,如果目标对象已经被包装过,那么它的类型肯定
* 会发生改变,因此也就需要一种机制来告诉容器包装后类型,否则
* 后续类型匹配就会出错,这个机制就是#predictBeanType(...)
*/
@Override
@Nullable
public Class<?> predictBeanType(Class<?> beanClass, String beanName) {
if (this.proxyTypes.isEmpty()) {
return null;
}
// 获取缓存key
Object cacheKey = getCacheKey(beanClass, beanName);
// proxyTypes的类型是Map<Object, Class<?>>
// 不管是JDK动态代理,还是CGLIB动态生成子类,最终都会改变
// 目标对象在容器中的类型,proxyTypes中保存着包装后的类型
return this.proxyTypes.get(cacheKey);
}
@Override
public Object getEarlyBeanReference(Object bean, String beanName) {
Object cacheKey = getCacheKey(bean.getClass(), beanName);
// earlyProxyReferences的类型是Map<Object, Object>
// getEarlyBeanReference(...)是最早能够访问到目标对象的地方
// 然而,目标对象可能会在后续的后处理中被改变,比如被其它的处理器修改。
// 但是只要在earlyProxyReferences中保存着原始目标对象,后续就可以
// 检测目标对象是否真的被改变了
this.earlyProxyReferences.put(cacheKey, bean);
// 尝试包装目标对象,画重点,织入的核心逻辑
return wrapIfNecessary(bean, beanName, cacheKey);
}
@Override
public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) {
Object cacheKey = getCacheKey(beanClass, beanName);
// targetSourcedBeans中保存着通过自定义TargetSourceCreator创建的目标对象
// 前面说过,#postProcessBeforeInstantiation(...)这个回调给了客户端全盘
// 接管Bean生命周期的机会,TargetSourceCreator这个工厂接口就是设计来让客户
// 端自行处理Bean的创建和属性注入等逻辑的。换言之,通过自定义TargetSourceCreator
// 返回的目标对象被认为是完全初始化了的,并且会跳过标准的Spring Bean生命周期管理,那么
// 这里就是最后的机会来完成织入并返回代理对象了
if (!StringUtils.hasLength(beanName) || !this.targetSourcedBeans.contains(beanName)) {
// advisedBeans的类型是Map<Object, Boolean>
// 如果值为false,表示当前这个Bean不需要被代理
// 值为true,表示已经被代理过了
// 那么如果不需要代理,肯定就直接返回了
// 如果已经代理过了,自然也不需要二次代理
// 所以这里才用containsKey(...)判断一下
if (this.advisedBeans.containsKey(cacheKey)) {
return null;
}
// 1、isInfrastructureClass()检测Bean所属的类是不是Spring AOP的支撑类
// 比如Advisor、Pointcut等等,这些类型是不需要被代理的
// 2、shouldSkip(...)给了子类一个机会来决定 beanClass + beanName 二元组
// 对应的Bean是不是不用进行代理
if (isInfrastructureClass(beanClass) || shouldSkip(beanClass, beanName)) {
this.advisedBeans.put(cacheKey, Boolean.FALSE);
return null;
}
}
// 如果用户确实需要全盘接管目标对象的生命周期
// 那么这里是最后一个机会来完成织入并返回代理对象了
TargetSource targetSource = getCustomTargetSource(beanClass, beanName);
if (targetSource != null) {
if (StringUtils.hasLength(beanName)) {
// 记录下来
this.targetSourcedBeans.add(beanName);
}
// 现在,目标对象已经到位 --> 从TargetSource中获取
// 接下来只要知道可以作用在目标对象上的Advisor都有
// 哪些就可以着手创建代理了
// step 1: 模板方法,由子类实现,返回所有可能的Advisor
Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(beanClass, beanName, targetSource);
// step 2: 根据已经掌握的信息 targetSouce + Advisors 来创建代理
Object proxy = createProxy(beanClass, beanName, specificInterceptors, targetSource);
// 代理创建完成以后,把它的类型记下来
this.proxyTypes.put(cacheKey, proxy.getClass());
return proxy;
}
return null;
}
@Override
public Object postProcessAfterInitialization(@Nullable Object bean, String beanName) {
if (bean != null) {
Object cacheKey = getCacheKey(bean.getClass(), beanName);
// 前面说过,earlyProxyReferences中保存着bean的原始引用
// 现在只需要简单判断一下就知道它有没有在其它地方被修改
// 如果是,那就不得不重新尝试一下对它进行代理了
if (this.earlyProxyReferences.remove(cacheKey) != bean) {
return wrapIfNecessary(bean, beanName, cacheKey);
}
}
return bean;
}
如果不考虑自定义TargetSourceCreator
这种非常规流程,AbstractAutoProxyCreator
一共有两个机会来完成织入,一处在getEarlyBeanReference(...)
,另一处在postProcessAfterInitialization(...)
。这两处都调用了wrapIfNecessary(...)
来完成最后的织入,继续往下看。
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;
}
// 对可能需要被代理类型,进一步检查它是否真的需要被代理
// 这一步的检测逻辑同 #postProcessBeforeInstantiation(...)
if (isInfrastructureClass(bean.getClass()) || shouldSkip(bean.getClass(), beanName)) {
this.advisedBeans.put(cacheKey, Boolean.FALSE);
return bean;
}
// step 1: 通过模板方法获取所有Advisor
Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null);
// 如果不为空,也就是配置了Advice,当然就需要被代理了
if (specificInterceptors != DO_NOT_PROXY) {
this.advisedBeans.put(cacheKey, Boolean.TRUE);
// strp 2: 根据 目标对象 + Advisors 这两份信息来创建代理
// createProxy(...)会根据配置信息来创建代理(jdk dynamic proxy/cglib subclassing)
// 并且,Advisors经过处理后会组成一个拦截器链,这一部分的内容比较复杂,我们下篇再说
Object proxy = createProxy(
bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource(bean));
// 记录下代理对象的类型
this.proxyTypes.put(cacheKey, proxy.getClass());
return proxy;
}
// 没有找到任何Advisor,也就是说没有配置任何Advice
// 那还代理给毛,自然就是false了
this.advisedBeans.put(cacheKey, Boolean.FALSE);
return bean;
}
wrapIfNecessary(...)
和postProcessBeforeInstantiation(...)
做的事情差不多,核心逻辑其实只有两步:
- 获取可以作用在目标对象上的
Advisor
集合 - 将第1步获取到的
Advisor list
转换成Interceptor list
并安装到Join point
上,说人话就是创建代理对象
createProxy(...)
整个流程比较复杂,涉及到Advice
的适配和扩展、拦截器链的初始化和安装、代理的创建等等,我们下篇再说。getAdvicesAndAdvisorsForBean(...)
是一个模板方法,实现它的是AbstractAutoProxyCreator
的子类AbstractAdvisorAutoProxyCreator
,接下来我们分析一下getAdvicesAndAdvisorsForBean(...)
。
AbstractAdvisorAutoProxyCreator是如何筛选Advisor的
getAdvicesAndAdvisorsForBean
@Override
@Nullable
protected Object[] getAdvicesAndAdvisorsForBean(Class<?> beanClass, String beanName,
@Nullable TargetSource targetSource) {
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) {
// 获取BeanFactory中所有的Advisor
List<Advisor> candidateAdvisors = findCandidateAdvisors();
// Sping AOP中Advisor的类型主要是PointcutAdvisor
// 这一步核心逻辑就是用Pointcut来对Advisor进行筛选
List<Advisor> eligibleAdvisors = findAdvisorsThatCanApply(candidateAdvisors, beanClass, beanName);
// 扩展方法,给子类一个增删改Advisor的机会
extendAdvisors(eligibleAdvisors);
if (!eligibleAdvisors.isEmpty()) {
// 对Advisor进行排序,默认通过Spring标准的Ordered接口和@Order注解指定优先级
eligibleAdvisors = sortAdvisors(eligibleAdvisors);
}
return eligibleAdvisors;
}
findEligibleAdvisors(...)
的流程还是比较清晰的:
- 找出容器中所有的Advisor
- 通过Pointcut进行筛选
- 对剩下的Advisor进行排序
findCandidateAdvisors
protected List<Advisor> findCandidateAdvisors() {
Assert.state(this.advisorRetrievalHelper != null, "No BeanFactoryAdvisorRetrievalHelper available");
return this.advisorRetrievalHelper.findAdvisorBeans();
}
发现它又代理给了advisorRetrievalHelper#findAdvisorBeans()
。
public List<Advisor> findAdvisorBeans() {
// 先读缓存
String[] advisorNames = this.cachedAdvisorBeanNames;
if (advisorNames == null) {
// 缓存没有的话,从BeanFactory中一次性把所有的Advisor Bean的名称获取出来
advisorNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(
this.beanFactory, Advisor.class, true, false);
this.cachedAdvisorBeanNames = advisorNames;
}
// BeanFactory中也没有,那就真的没有了
if (advisorNames.length == 0) {
return new ArrayList<>();
}
// 否则的话,根据beanName挨个调用getBean(...)
List<Advisor> advisors = new ArrayList<>();
for (String name : advisorNames) {
// 首先判断一下这个name所代表的Advisor是否符合条件,默认返回true
// 可由AbstractAdvisorAutoProxyCreator及其子类进行改写,比如
// InfrastructureAdvisorAutoProxyCreator就要求Advisor的角色
// 必须是ROLE_INFRASTRUCTURE,所以@EnableCaching/@EnableTransactionManagement
// 导入的一票Advisor的role都是ROLE_INFRASTRUCTURE
if (isEligibleBean(name)) {
// 跳过正在初始化的Advisor,毕竟这种的拿了也没用
if (this.beanFactory.isCurrentlyInCreation(name)) {
if (logger.isTraceEnabled()) {
logger.trace("Skipping currently created advisor '" + name + "'");
}
}
else {
try {
// 逐个获取
advisors.add(this.beanFactory.getBean(name, Advisor.class));
}
catch (BeanCreationException ex) {
// 如果目标对象和附加在它之上的Advisor间存在循环依赖
// 这也是抛出BeanCurrentlyInCreationException异常的原因
// 对这种情况,忽略这个Advisor
// 个人感觉这种情况是否还是抛出异常比较好?
Throwable rootCause = ex.getMostSpecificCause();
if (rootCause instanceof BeanCurrentlyInCreationException) {
BeanCreationException bce = (BeanCreationException) rootCause;
String bceBeanName = bce.getBeanName();
if (bceBeanName != null && this.beanFactory.isCurrentlyInCreation(bceBeanName)) {
if (logger.isTraceEnabled()) {
logger.trace("Skipping advisor '" + name +
"' with dependency on currently created bean: " + ex.getMessage());
}
continue;
}
}
throw ex;
}
}
}
}
return advisors;
}
findAdvisorsThatCanApply
protected List<Advisor> findAdvisorsThatCanApply(
List<Advisor> candidateAdvisors, Class<?> beanClass, String beanName) {
// 在ThreadLocal中记录一下beanName
// 用在spring自定义的 bean() AspectJ表达式中,不是很常用
ProxyCreationContext.setCurrentProxiedBeanName(beanName);
try {
return AopUtils.findAdvisorsThatCanApply(candidateAdvisors, beanClass);
}
finally {
ProxyCreationContext.setCurrentProxiedBeanName(null);
}
}
核心逻辑都在AopUtils
中了。
public static List<Advisor> findAdvisorsThatCanApply(List<Advisor> candidateAdvisors, Class<?> clazz) {
if (candidateAdvisors.isEmpty()) {
return candidateAdvisors;
}
List<Advisor> eligibleAdvisors = new ArrayList<>();
// IntroductionAdvisor我们就不说了,用得比较少
for (Advisor candidate : candidateAdvisors) {
if (candidate instanceof IntroductionAdvisor && canApply(candidate, clazz)) {
eligibleAdvisors.add(candidate);
}
}
boolean hasIntroductions = !eligibleAdvisors.isEmpty();
for (Advisor candidate : candidateAdvisors) {
if (candidate instanceof IntroductionAdvisor) {
// already processed
continue;
}
// 判断Advisor能否适用于此beanClass
if (canApply(candidate, clazz, hasIntroductions)) {
eligibleAdvisors.add(candidate);
}
}
return eligibleAdvisors;
}
public static boolean canApply(Advisor advisor, Class<?> targetClass, boolean hasIntroductions) {
// 忽略IntroductionAdvisor吧,我们不讲它
// 毕竟PointcutAdvisor几乎就能代表spring中的Advisor了
if (advisor instanceof IntroductionAdvisor) {
return ((IntroductionAdvisor) advisor).getClassFilter().matches(targetClass);
}
// 如果是PointcutAdvisor
else if (advisor instanceof PointcutAdvisor) {
PointcutAdvisor pca = (PointcutAdvisor) advisor;
// 使用Pointcut进行筛选
return canApply(pca.getPointcut(), targetClass, hasIntroductions);
}
else {
// Pointcut都没有的话默认它可以
// 简单理解,这是一种generic advisor
return true;
}
}
public static boolean canApply(Pointcut pc, Class<?> targetClass, boolean hasIntroductions) {
Assert.notNull(pc, "Pointcut must not be null");
// 首先看看类型是否匹配
if (!pc.getClassFilter().matches(targetClass)) {
return false;
}
// Special case: MethodMatcher.TRUE 对任何方法都返回match
MethodMatcher methodMatcher = pc.getMethodMatcher();
if (methodMatcher == MethodMatcher.TRUE) {
// 自然没有判断的必要
return true;
}
// 忽略Introduction吧
IntroductionAwareMethodMatcher introductionAwareMethodMatcher = null;
if (methodMatcher instanceof IntroductionAwareMethodMatcher) {
introductionAwareMethodMatcher = (IntroductionAwareMethodMatcher) methodMatcher;
}
Set<Class<?>> classes = new LinkedHashSet<>();
// 获取targetClass的原始类型,只有原始类型上才可能存在用户定义的方法
// 也只有这些方法才有必要判断它是否匹配
// 1. 不能是jdk dymamic proxy,jdk dynamic proxy上就不可能有
if (!Proxy.isProxyClass(targetClass)) {
// 2. 虽然不是jdk dynamic proxy,但有可能是cglib动态生成的子类啊,
// cglib动态生成的子类也不可能有,所以需要获取一下user class
classes.add(ClassUtils.getUserClass(targetClass));
}
// targetClass所实现接口也获取一下,接口中会定义方法,
// 方法上可能有注解,而这些注解,有可能就是判断条件,比如说
// spring-tx的@Transactional是可以标注在接口上的
classes.addAll(ClassUtils.getAllInterfacesForClassAsSet(targetClass));
for (Class<?> clazz : classes) {
// 这没啥说的了,所有方法拿出来,逐个使用MethodMatcher判断一下
// 这里不涉及isRuntime()的情况,那种情况需要方法被实际调用了才能判断
// 对jdk dynamic proxy来说就是InvocationHandler#invoke(...)被调用的时候
Method[] methods = ReflectionUtils.getAllDeclaredMethods(clazz);
for (Method method : methods) {
if (introductionAwareMethodMatcher != null ?
introductionAwareMethodMatcher.matches(method, targetClass, hasIntroductions) :
methodMatcher.matches(method, targetClass)) {
return true;
}
}
}
return false;
}
sortAdvisors
protected List<Advisor> sortAdvisors(List<Advisor> advisors) {
AnnotationAwareOrderComparator.sort(advisors);
return advisors;
}
默认的排序策略是很简单的,根据Advisor
实现的Ordered
接口或标注的Order
注解提供的优先级进行排序。
结语
本篇我们从EnableAspectJAutoProxy
注解着手,一步一步分析了spring-aop
是如何通过BeanPostProcessor
来执行织入的,下一篇我们一起看看创建动态代理的全流程吧~~
网友评论