你知道Spring是怎么将AOP应用到Bean的生命周期中的吗?程序员书单关注共 12905字,需浏览 26分钟 ·2020-07-28 12:36 ”在上篇文章中(Spring中AOP相关的API及源码解析,原来AOP是这样子的)我们已经分析过了AOP的实现的源码,那么Spring是如何将AOP应用到Bean的生命周期的呢?这篇文章就带着大家来探究下这个问题。本文我们要分析的代码还是位于org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#doCreateBean这个方法中,在《我们来谈一谈Spring中的属性注入 》这篇文章中,我们已经分析过了populateBean这个方法,所以本文我们接着来看看initializeBean这个方法,它主要干了这么几件事执行Aware接口中的方法执行生命周期回调方法完成AOP代理对应源码如下:protected Object initializeBean(String beanName, Object bean, @Nullable RootBeanDefinition mbd) { if (System.getSecurityManager() != null) { AccessController.doPrivileged((PrivilegedAction) () -> { 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注解向容器中注册一个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也是不需要被代理的,只不过不是在这个方法中处理的。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#getAdvicesAndAdvisorsForBeanprotected Object[] getAdvicesAndAdvisorsForBean( Class beanClass, String beanName, @Nullable TargetSource targetSource) { // 通过findEligibleAdvisors方法返回对应的通知 // 这个方法会返回所有能应用在指定的Bean上的通知 List advisors = findEligibleAdvisors(beanClass, beanName); if (advisors.isEmpty()) { return DO_NOT_PROXY; } return advisors.toArray();}第二步:调用org.springframework.aop.framework.autoproxy.AbstractAdvisorAutoProxyCreator#findEligibleAdvisorsprotected List findEligibleAdvisors(Class beanClass, String beanName) { // 获取到所有的通知 List candidateAdvisors = findCandidateAdvisors(); // 从获取到的通知中筛选出能应用到这个Bean上的通知 List eligibleAdvisors = findAdvisorsThatCanApply(candidateAdvisors, beanClass, beanName); extendAdvisors(eligibleAdvisors); if (!eligibleAdvisors.isEmpty()) { eligibleAdvisors = sortAdvisors(eligibleAdvisors); } return eligibleAdvisors;}第三步:调用org.springframework.aop.aspectj.annotation.AnnotationAwareAspectJAutoProxyCreator#findCandidateAdvisors获取到所有的通知// 这个方法的目的就是为了获取到所有的通知protected List findCandidateAdvisors() { // 先调用父类的方法,父类会去查找容器中所有属于Advisor类型的Bean List 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 buildAspectJAdvisors() { List aspectNames = this.aspectBeanNames; if (aspectNames == null) { synchronized (this) { aspectNames = this.aspectBeanNames; if (aspectNames == null) { List 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 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#findAdvisorsThatCanApplyprotected List findAdvisorsThatCanApply( List candidateAdvisors, Class beanClass, String beanName) { ProxyCreationContext.setCurrentProxiedBeanName(beanName); try { return AopUtils.findAdvisorsThatCanApply(candidateAdvisors, beanClass); } finally { ProxyCreationContext.setCurrentProxiedBeanName(null); }}这个方法其实没啥好分析的,就是根据前面找出来的Advisor集合进行遍历,然后根据每个Advisor对应的切点来进行匹配,如何合适就返回,对应源码也比较简单,当然前提是你看过我之前那篇AOP源码分析的文章了.总结这篇文章比较短,因为没有做很细节的源码分析,比较详细的源码分析已经放到上篇文章中了。最后我这里画个流程图总结一下AOP是怎么被应用到Bean的生命周期中的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 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中的循环依赖如果我的文章能帮到你,记得点个赞哈~!我叫DMZ,一个在学习路上匍匐前行的小菜鸟!— 【 THE END 】—本公众号全部博文已整理成一个目录,请在公众号里回复「m」获取!3T技术资源大放送!包括但不限于:Java、C/C++,Linux,Python,大数据,人工智能等等。在公众号内回复「1024」,即可免费获取!! 浏览 44点赞 评论 收藏 分享 手机扫一扫分享分享 举报 评论图片表情视频评价全部评论推荐 你能说说Spring框架中Bean的生命周期吗?三太子敖丙0Spring Bean 的生命周期java12340【02期】你能说说Spring框架中Bean的生命周期吗?程序员的成长之路0面试官:你能说说Spring框架中Bean的生命周期吗?我是程序汪0Spring 中的bean 是线程安全的吗?路人甲Java0Spring 中的 bean 是线程安全的吗?Java技术精选0Spring 中的 bean 是线程安全的吗?程序员的成长之路0Spring 中的bean 是线程安全的吗?我是程序汪0Spring 中的 bean 是线程安全的吗?JAVA葵花宝典0Spring 中的bean 是线程安全的吗?Java研发军团0点赞 评论 收藏 分享 手机扫一扫分享分享 举报