乐趣区

你知道Spring是怎么将AOP应用到Bean的生命周期中的吗

聊一聊 Spring 是怎么将 AOP 应用到 Bean 的生命周期中的?

本系列文章:

听说你还没学 Spring 就被源码编译劝退了?30+ 张图带你玩转 Spring 编译

读源码,我们可以从第一行读起

你知道 Spring 是怎么解析配置类的吗?

配置类为什么要添加 @Configuration 注解?

谈谈 Spring 中的对象跟 Bean,你知道 Spring 怎么创建对象的吗?

这篇文章,我们来谈一谈 Spring 中的属性注入

Spring 中 AOP 相关的 API 及源码解析,原来 AOP 是这样子的

推荐阅读:

Spring 官网阅读 | 总结篇

Spring 杂谈

本系列文章将会带你一行行的将 Spring 的源码吃透,推荐阅读的文章是阅读源码的基础!

前言

在上篇文章中(Spring 中 AOP 相关的 API 及源码解析,原来 AOP 是这样子的)我们已经分析过了 AOP 的实现的源码,那么 Spring 是如何将 AOP 应用到 Bean 的生命周期的呢?这篇文章就带着大家来探究下这个问题。本文我们要分析的代码还是位于 org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#doCreateBean 这个方法中,在《我们来谈一谈 Spring 中的属性注入》这篇文章中,我们已经分析过了 populateBean 这个方法,

image-20200703202825887

所以本文我们接着来看看 initializeBean 这个方法,它主要干了这么几件事

  1. 执行 Aware 接口中的方法
  2. 执行 生命周期回调方法
  3. 完成 AOP 代理

对应源码如下:

protected Object initializeBean(String beanName, Object bean, @Nullable RootBeanDefinition mbd) {if (System.getSecurityManager() != null) {AccessController.doPrivileged((PrivilegedAction<Object>) () -> {    invokeAwareMethods(beanName, bean);    return null;   }, getAccessControlContext());  }  else {// 执行 Aware 接口中的方法   invokeAwareMethods(beanName, bean);  }  Object wrappedBean = bean;  if (mbd == null || !mbd.isSynthetic()) {// 调用 InitDestroyAnnotationBeanPostProcessor            // 的 postProcessBeforeInitialization 方法            // 处理 @PostContructor 注解标注的方法            // 另外有一部分 aware 方法也是在这里调用的   wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);  }  try {// 如果实现了 InitializingBean,会调用 afterPropertiesSet 方法            // 如果 XML 中配置了 init-method 属性,会调用对应的初始化方法   invokeInitMethods(beanName, wrappedBean, mbd);  }  catch (Throwable ex) {throw new BeanCreationException(     (mbd != null ? mbd.getResourceDescription() : null),     beanName, "Invocation of init method failed", ex);  }  if (mbd == null || !mbd.isSynthetic()) {// 在这里完成 AOP   wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);  }  return wrappedBean; }

因为在 Spring 官网阅读(九)Spring 中 Bean 的生命周期(上)文章中我们已经对这个方法做过分析了,并且这个方法本身也比较简单,所以不再对这个方法做过多赘述,我们主要关注的就是 Spring 是如何将 AOP 应用到 Bean 的生命周期中的,对应的就是 applyBeanPostProcessorsAfterInitialization 这个方法,其源码如下:

public Object applyBeanPostProcessorsAfterInitialization(Object existingBean, String beanName)    throws BeansException {Object result = existingBean;    for (BeanPostProcessor processor : getBeanPostProcessors()) {Object current = processor.postProcessAfterInitialization(result, beanName);        if (current == null) {return result;}        result = current;    }    return result;}

实际上就是调用了所有后置处理器的 postProcessAfterInitialization 方法,在 Spring 中 AOP 相关的 API 及源码解析,原来 AOP 是这样子的一文中已经提到过了,@EnableAspectJAutoProxy注解实际上就是向容器中注册了一个 AnnotationAwareAspectJAutoProxyCreator,这个类本身就是一个后置处理器,AOP 代理 就是由它在这一步完成的。

Bean 生命周期中 AOP 的流程

1、@EnableAspectJAutoProxy

通过 @EnableAspectJAutoProxy 注解向容器中注册一个 AnnotationAwareAspectJAutoProxyCreatorBeanDefinition,它本身也是一个 BeanPostProcessor,这个BeanDefinition 会在 org.springframework.context.support.AbstractApplicationContext#registerBeanPostProcessors 这个方法中完成创建,如下图所示

image-20200704112937846

2、postProcessBeforeInstantiation 方法执行

执行 AnnotationAwareAspectJAutoProxyCreatorpostProcessBeforeInstantiation方法,实际上就是父类 AbstractAutoProxyCreatorpostProcessBeforeInstantiation被执行

对应源码如下:

//  这个方法的主要目的就是在不考虑通知的情况下,确认哪些 Bean 不需要被代理 //  1.Advice,Advisor,Pointcut 类型的 Bean 不需要被代理 //  2. 不是原始 Bean 被包装过的 Bean 不需要被代理,例如 ScopedProxyFactoryBean//  实际上并不只是这些 Bean 不需要被代理,如果没有对应的通知需要被应用到这个 Bean 上的话 //  这个 Bean 也是不需要被代理的,只不过不是在这个方法中处理的。public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) {Object cacheKey = getCacheKey(beanClass, beanName);    // 如果 beanName 为空或者为这个 bean 提供了定制的 targetSource    if (!StringUtils.hasLength(beanName) || !this.targetSourcedBeans.contains(beanName)) {// advisedBeans 是一个 map, 其中 key 是 BeanName,value 代表了这个 Bean 是否需要被代理        // 如果已经包含了这个 key, 不需要在进行判断了,直接返回即可        // 因为这个方法的目的就是在实例化前就确认哪些 Bean 是不需要进行 AOP 的        if (this.advisedBeans.containsKey(cacheKey)) {return null;}        // 说明还没有对这个 Bean 进行处理        // 在这里会对 SpringAOP 中的基础设施 bean, 例如 Advice,Pointcut,Advisor 做标记        // 标志它们不需要被代理,对应的就是将其放入到 advisedBeans 中,value 设置为 false        // 其次,如果这个 Bean 不是最原始的 Bean,那么也不进行代理,也将其 value 设置为 false        if (isInfrastructureClass(beanClass) || shouldSkip(beanClass, beanName)) {this.advisedBeans.put(cacheKey, Boolean.FALSE);            return null;        }    }    // 是否为这个 Bean 提供了定制的 TargetSource    // 如果提供了定制的 TargetSource,那么直接在这一步创建一个代理对象并返回    // 一般不会提供    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;}

3、postProcessAfterInitialization 方法执行

实际上也是执行父类 AbstractAutoProxyCreator 中的方法,对应源码如下:

public Object postProcessAfterInitialization(@Nullable Object bean, String beanName) {if (bean != null) {Object cacheKey = getCacheKey(bean.getClass(), beanName);        // 什么时候这个判断会成立呢?// 如果不出现循环引用的话,remove 方法必定返回 null        // 所以这个 remove(cacheKey) != bean 肯定会成立        // 如果发生循环依赖的话,这个判断就不会成立        // 这个我们在介绍循环依赖的时候再详细分析,// 目前你只需要知道 wrapIfNecessary 完成了 AOP 代理        if (this.earlyProxyReferences.remove(cacheKey) != bean) {// 需要代理的话,在这里完成的代理            return wrapIfNecessary(bean, beanName, cacheKey);        }    }    return bean;}

4、wrapIfNecessary 方法执行

protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {// 在 postProcessBeforeInstantiation 方法中可能已经完成过代理了    // 如果已经完成代理了,那么直接返回这个代理的对象    if (StringUtils.hasLength(beanName) && this.targetSourcedBeans.contains(beanName)) {return bean;}        // 在 postProcessBeforeInstantiation 方法中可能已经将其标记为不需要代理了    // 这种情况下,也直接返回这个 Bean    if (Boolean.FALSE.equals(this.advisedBeans.get(cacheKey))) {return bean;}        // 跟在 postProcessBeforeInstantiation 方法中的逻辑一样    // 如果不需要代理,直接返回,同时在 advisedBeans 中标记成 false    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);        // 到这里创建代理,实际上底层就是 new 了一个 ProxyFactory 来创建代理的        Object proxy = createProxy(bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource(bean));        this.proxyTypes.put(cacheKey, proxy.getClass());        return proxy;    } // 如果没有通知的话,也将这个 Bean 标记为不需要代理    this.advisedBeans.put(cacheKey, Boolean.FALSE);    return bean;}

关于创建代理的具体源码分析,在 Spring 中 AOP 相关的 API 及源码解析,原来 AOP 是这样子的一文中已经做了详细介绍,所以本文不再赘述,现在我们的重点将放在 Spring 是如何解析出来通知的,对应方法就是getAdvicesAndAdvisorsForBean,其源码如下:

第一步:调用org.springframework.aop.framework.autoproxy.AbstractAdvisorAutoProxyCreator#getAdvicesAndAdvisorsForBean

protected Object[] getAdvicesAndAdvisorsForBean(      Class<?> beanClass, String beanName, @Nullable TargetSource targetSource) {// 通过 findEligibleAdvisors 方法返回对应的通知   // 这个方法回返回所有能应用在指定的 Bean 上的通知   List<Advisor> advisors = findEligibleAdvisors(beanClass, beanName);      if (advisors.isEmpty()) {return DO_NOT_PROXY;}   return advisors.toArray();}

第二步:调用org.springframework.aop.framework.autoproxy.AbstractAdvisorAutoProxyCreator#findEligibleAdvisors

protected List<Advisor> findEligibleAdvisors(Class<?> beanClass, String beanName) {// 获取到所有的通知    List<Advisor> candidateAdvisors = findCandidateAdvisors();    // 从获取到的通知中筛选出能应用到这个 Bean 上的通知    List<Advisor> eligibleAdvisors = findAdvisorsThatCanApply(candidateAdvisors, beanClass, beanName);    extendAdvisors(eligibleAdvisors);    if (!eligibleAdvisors.isEmpty()) {eligibleAdvisors = sortAdvisors(eligibleAdvisors);    }    return eligibleAdvisors;}

第三步:调用 org.springframework.aop.aspectj.annotation.AnnotationAwareAspectJAutoProxyCreator#findCandidateAdvisors 获取到所有的通知

// 这个方法的目的就是为了获取到所有的通知 protected List<Advisor> findCandidateAdvisors() {       // 先调用父类的方法,父类会去查找容器中所有属于 Advisor 类型的 Bean    List<Advisor> advisors = super.findCandidateAdvisors();       // 这个类本身会通过一个 aspectJAdvisorsBuilder 来构建通知    // 构建的逻辑就是解析 @Aspect 注解所标注的类中的方法    if (this.aspectJAdvisorsBuilder != null) {advisors.addAll(this.aspectJAdvisorsBuilder.buildAspectJAdvisors());    }        // 最后返回这些通知    return advisors;}

第四步:org.springframework.aop.aspectj.annotation.BeanFactoryAspectJAdvisorsBuilder#buildAspectJAdvisors构建通知,这个方法比较长,我们就只分析其中的关键代码即可

public List<Advisor> buildAspectJAdvisors() {  List<String> aspectNames = this.aspectBeanNames;  if (aspectNames == null) {synchronized (this) {aspectNames = this.aspectBeanNames;    if (aspectNames == null) {List<Advisor> advisors = new ArrayList<>();     aspectNames = new ArrayList<>();     // 会获取到容器中的所有 BeanName     String[] beanNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(this.beanFactory, Object.class, true, false);     for (String beanName : beanNames) {// 如果对 beanName 配置了正则匹配的话,那么要按照正则表达式的匹配规则进行过滤      // 默认是没有的,可以认为 isEligibleBean 始终返回 true      if (!isEligibleBean(beanName)) {continue;}      // We must be careful not to instantiate beans eagerly as in this case they      // would be cached by the Spring container but would not have been weaved.      Class<?> beanType = this.beanFactory.getType(beanName);      if (beanType == null) {continue;}      // 判断类上是否添加了 @Aspect 注解      if (this.advisorFactory.isAspect(beanType)) {aspectNames.add(beanName);       AspectMetadata amd = new AspectMetadata(beanType, beanName);       // 默认就是 SINGLETON,代理切面对象是单例的       if (amd.getAjType().getPerClause().getKind() == PerClauseKind.SINGLETON) {// 最后从这个切面实例中解析出所有的通知                            // 关于通知解析的具体代码就不再分析了         MetadataAwareAspectInstanceFactory factory =          new BeanFactoryAspectInstanceFactory(this.beanFactory, beanName);        List<Advisor> classAdvisors = this.advisorFactory.getAdvisors(factory);        if (this.beanFactory.isSingleton(beanName)) {this.advisorsCache.put(beanName, classAdvisors);        }        else {this.aspectFactoryCache.put(beanName, factory);        }        advisors.addAll(classAdvisors);       }  // 省略部分代码  return advisors; }

第五步:org.springframework.aop.framework.autoproxy.AbstractAdvisorAutoProxyCreator#findAdvisorsThatCanApply

protected List<Advisor> findAdvisorsThatCanApply(List<Advisor> candidateAdvisors, Class<?> beanClass, String beanName) {ProxyCreationContext.setCurrentProxiedBeanName(beanName);    try {return AopUtils.findAdvisorsThatCanApply(candidateAdvisors, beanClass);    }    finally {ProxyCreationContext.setCurrentProxiedBeanName(null);    }}

这个方法其实没啥好分析的,就是根据前面找出来的 Advisor 集合进行遍历,然后根据每个 Advisor 对应的切点来进行匹配,如何合适就返回,对应源码也比较简单,当然前提是你看过我之前那篇 AOP 源码分析 的文章了.

总结

这篇文章比较短, 因为没有做很细节的源码分析, 比较详细的源码分析已经放到上篇文章中了。最后我这里画个流程图总结一下 AOP 是怎么被应用到 Bean 的生命周期中的

image-20200705152704917

Spring 源码的最后一点补充

protected Object doCreateBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)    throws BeanCreationException {// 1. 实例化    ---> createBeanInstance    // 2. 属性注入  ---> populateBean    // 3. 初始化    ---> 完成初始化及 AOP    // exposedObject 就是完成初始化后的 Bean      // 省略部分代码,省略代码的作用已经在上面标明了        // 下面的代码实际上主要目的在于处理循环依赖    if (earlySingletonExposure) {Object earlySingletonReference = getSingleton(beanName, false);        if (earlySingletonReference != null) {if (exposedObject == bean) {exposedObject = earlySingletonReference;}            // 我们之前早期暴露出去的 Bean 跟现在最后要放到容器中的 Bean 不是同一个            // allowRawInjectionDespiteWrapping 为 false            // 并且当前 Bean 被当成依赖注入到了别的 Bean 中            else if (!this.allowRawInjectionDespiteWrapping && hasDependentBean(beanName)) {// 获取到当前 Bean 所从属的 Bean                String[] dependentBeans = getDependentBeans(beanName);                // 要得到真实的从属的 Bean                Set<String> actualDependentBeans = new LinkedHashSet<>(dependentBeans.length);                for (String dependentBean : dependentBeans) {// 移除那些仅仅为了类型检查而创建出来                    if (!removeSingletonIfCreatedForTypeCheckOnly(dependentBean)) {actualDependentBeans.add(dependentBean);                    }                }                if (!actualDependentBeans.isEmpty()) {// 抛出异常                    // 出现了循环依赖,并且实际存在容器中的 Bean 跟被当作依赖注入到别的 Bean 中的                    // 不是同一个对象,这个时候也报错}            }        }    }    // 注册 bean 的销毁回调    try {registerDisposableBeanIfNecessary(beanName, bean, mbd);    }    catch (BeanDefinitionValidationException ex) {throw new BeanCreationException(            mbd.getResourceDescription(), beanName, "Invalid destruction signature", ex);    }    return exposedObject;}

实际这段代码还是跟循环依赖相关,循环依赖是 Spring 中一个比较重要的话题,不管是为了面试还是更好的了解清楚 Spring 的流程都很有必要去弄懂它

关于 Spring 的循环依赖,我将在下篇文章专门分析!

如果本文对你有帮助的话,记得点个赞吧!也欢迎关注我的公众号,微信搜索:程序员 DMZ,或者扫描下方二维码,跟着我一起认认真真学 Java, 踏踏实实做一个 coder。

公众号

我叫 DMZ,一个在学习路上匍匐前行的小菜鸟!

退出移动版