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

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

本系列文章:程序员

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

读源码,咱们能够从第一行读起面试

你知道Spring是怎么解析配置类的吗?正则表达式

配置类为何要添加@Configuration注解?spring

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

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

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
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的流程

一、@EnableAspectJAutoProxy

经过@EnableAspectJAutoProxy注解向容器中注册一个AnnotationAwareAspectJAutoProxyCreatorBeanDefinition,它自己也是一个BeanPostProcessor,这个BeanDefinition会在org.springframework.context.support.AbstractApplicationContext#registerBeanPostProcessors这个方法中完成建立,以下图所示

image-20200704112937846
image-20200704112937846

二、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; } 复制代码

三、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; } 复制代码

四、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
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,一个在学习路上匍匐前行的小菜鸟!

相关文章
相关标签/搜索