美文网首页Java
你知道Spring是怎么将AOP应用到Bean的生命周期中的吗?

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

作者: 愿天堂没有BUG | 来源:发表于2022-06-28 15:30 被阅读0次

    Spring是如何将AOP应用到Bean的生命周期的呢?这篇文章就带着大家来探究下这个问题。本文我们要分析的代码还是位于

    org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#doCreateBean这个方法中,我们之前分析过了 populateBean这个方法,

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

    执行Aware接口中的方法

    执行生命周期回调方法

    完成AOP代理

    对应源码如下:

    protectedObjectinitializeBean(StringbeanName,Objectbean,@NullableRootBeanDefinition mbd) {if(System.getSecurityManager() !=null) {AccessController.doPrivileged((PrivilegedAction) () -> {invokeAwareMethods(beanName, bean);returnnull;}, getAccessControlContext());}else{// 执行Aware接口中的方法invokeAwareMethods(beanName, bean);}ObjectwrappedBean = 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) {thrownewBeanCreationException((mbd !=null? mbd.getResourceDescription() :null),beanName,"Invocation of init method failed", ex);}if(mbd ==null|| !mbd.isSynthetic()) {// 在这里完成AOPwrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);}returnwrappedBean;}

    我们主要关注的就是Spring是如何将AOP应用到Bean的生命周期中的,对应的就是

    applyBeanPostProcessorsAfterInitialization这个方法,其源码如下:

    publicObject applyBeanPostProcessorsAfterInitialization(Object existingBean, String beanName)throwsBeansException {Objectresult = existingBean;for(BeanPostProcessor processor : getBeanPostProcessors()) {Objectcurrent = processor.postProcessAfterInitialization(result, beanName);if(current == null) {returnresult;}result=current;}returnresult;}

    实际上就是调用了所有后置处理器的

    postProcessAfterInitialization方法,,@EnableAspectJAutoProxy注解实际上就是向容器中注册了一个AnnotationAwareAspectJAutoProxyCreator,这个类本身就是一个后置处理器,AOP代理就是由它在这一步完成的。

    Bean生命周期中AOP的流程

    1、@EnableAspectJAutoProxy

    通过@EnableAspectJAutoProxy注解向容器中注册一个

    AnnotationAwareAspectJAutoProxyCreator的BeanDefinition,它本身也是一个BeanPostProcessor,这个BeanDefinition会在org.springframework.context.support.AbstractApplicationContext#registerBeanPostProcessors这个方法中完成创建,如下图所示

    2、postProcessBeforeInstantiation方法执行

    执行

    AnnotationAwareAspectJAutoProxyCreator的postProcessBeforeInstantiation方法,实际上就是父类AbstractAutoProxyCreator的postProcessBeforeInstantiation被执行

    对应源码如下:

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

    3、postProcessAfterInitialization方法执行

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

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

    4、wrapIfNecessary方法执行

    protectedObject wrapIfNecessary(Object bean, String beanName, Object cacheKey) {// 在postProcessBeforeInstantiation方法中可能已经完成过代理了// 如果已经完成代理了,那么直接返回这个代理的对象if(StringUtils.hasLength(beanName) &&this.targetSourcedBeans.contains(beanName)) {returnbean;    }// 在postProcessBeforeInstantiation方法中可能已经将其标记为不需要代理了// 这种情况下,也直接返回这个Beanif(Boolean.FALSE.equals(this.advisedBeans.get(cacheKey))) {returnbean;    }// 跟在postProcessBeforeInstantiation方法中的逻辑一样// 如果不需要代理,直接返回,同时在advisedBeans中标记成falseif(isInfrastructureClass(bean.getClass()) || shouldSkip(bean.getClass(), beanName)) {this.advisedBeans.put(cacheKey,Boolean.FALSE);returnbean;    }// 获取可以应用到这个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());returnproxy;    }// 如果没有通知的话,也将这个Bean标记为不需要代理this.advisedBeans.put(cacheKey,Boolean.FALSE);returnbean;}

    现在我们的重点将放在Spring是如何解析出来通知的,对应方法就是

    getAdvicesAndAdvisorsForBean,其源码如下:

    第一步:调用

    org.springframework.aop.framework.autoproxy.AbstractAdvisorAutoProxyCreator#getAdvicesAndAdvisorsForBean

    protectedObject[] getAdvicesAndAdvisorsForBean(      Class beanClass, String beanName,@NullableTargetSource targetSource) {// 通过findEligibleAdvisors方法返回对应的通知// 这个方法回返回所有能应用在指定的Bean上的通知List advisors = findEligibleAdvisors(beanClass, beanName);if(advisors.isEmpty()) {returnDO_NOT_PROXY;  }returnadvisors.toArray();}

    第二步:调用

    org.springframework.aop.framework.autoproxy.AbstractAdvisorAutoProxyCreator#findEligibleAdvisors

    protectedList findEligibleAdvisors(ClassbeanClass,StringbeanName){// 获取到所有的通知List candidateAdvisors = findCandidateAdvisors();// 从获取到的通知中筛选出能应用到这个Bean上的通知List eligibleAdvisors = findAdvisorsThatCanApply(candidateAdvisors, beanClass, beanName);    extendAdvisors(eligibleAdvisors);if(!eligibleAdvisors.isEmpty()) {        eligibleAdvisors = sortAdvisors(eligibleAdvisors);    }returneligibleAdvisors;}

    第三步:调用

    org.springframework.aop.aspectj.annotation.AnnotationAwareAspectJAutoProxyCreator#findCandidateAdvisors获取到所有的通知

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

    第四步:

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

    publicList buildAspectJAdvisors() {List aspectNames =this.aspectBeanNames;if(aspectNames ==null) {synchronized (this) {aspectNames =this.aspectBeanNames;if(aspectNames ==null) {List advisors = new ArrayList<>();aspectNames = new ArrayList<>();// 会获取到容器中的所有BeanNameString[] beanNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(this.beanFactory, Object.class,true,false);for(String beanName : beanNames) {// 如果对beanName配置了正则匹配的话,那么要按照正则表达式的匹配规则进行过滤// 默认是没有的,可以认为isEligibleBean始终返回trueif(!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 classAdvisors =this.advisorFactory.getAdvisors(factory);if(this.beanFactory.isSingleton(beanName)) {this.advisorsCache.put(beanName, classAdvisors);}else{this.aspectFactoryCache.put(beanName, factory);}advisors.addAll(classAdvisors);}// 省略部分代码returnadvisors;}

    第五步:

    org.springframework.aop.framework.autoproxy.AbstractAdvisorAutoProxyCreator#findAdvisorsThatCanApply

    protectedList findAdvisorsThatCanApply(List candidateAdvisors,ClassbeanClass,StringbeanName){    ProxyCreationContext.setCurrentProxiedBeanName(beanName);try{returnAopUtils.findAdvisorsThatCanApply(candidateAdvisors, beanClass);    }finally{        ProxyCreationContext.setCurrentProxiedBeanName(null);    }}

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

    总结

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

    Spring源码的最后一点补充

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

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

    相关文章

      网友评论

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

        本文链接:https://www.haomeiwen.com/subject/geoavrtx.html