17

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

 4 years ago
source link: https://segmentfault.com/a/1190000023098042
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

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

前言

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

2uyEryr.png!web

image-20200703202825887

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

Aware
生命周期回调方法
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 这个方法中完成创建,如下图所示

quERni3.png!web

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的生命周期中的

IzE3uqj.png!web

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。

rmmiQzi.jpg!web

公众号

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


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK