你知道Spring是怎么将AOP应用到Bean的生命周期中的吗?
聊一聊Spring是怎么将AOP应用到Bean的生命周期中的?
本系列文章:
听说你还没学Spring就被源码编译劝退了?30+张图带你玩转Spring编译
谈谈Spring中的对象跟Bean,你知道Spring怎么创建对象的吗?
Spring中AOP相关的API及源码解析,原来AOP是这样子的
推荐阅读:
本系列文章将会带你一行行的将Spring的源码吃透,推荐阅读的文章是阅读源码的基础!
前言
在上篇文章中(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<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注解向容器中注册一个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#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的生命周期中的

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,一个在学习路上匍匐前行的小菜鸟!
你知道Spring是怎么将AOP应用到Bean的生命周期中的吗?的更多相关文章
- Spring框架系列(8) - Spring IOC实现原理详解之Bean实例化(生命周期,循环依赖等)
上文,我们看了IOC设计要点和设计结构:以及Spring如何实现将资源配置(以xml配置为例)通过加载,解析,生成BeanDefination并注册到IoC容器中的:容器中存放的是Bean的定义即Be ...
- Spring的BeanPostProcessor后置处理器与bean的生命周期
前言 本文将把Spring在Bean的生命周期中涉及到的后置处理器一一梳理出来,并简要说一下功能,至于每个后置处理器在实际扩展中的用处,还要后续慢慢探索总结. 正文 下面一步步跟进探寻那些后置处理器们 ...
- Spring第三天,详解Bean的生命周期,学会后让面试官无话可说!
点击下方链接回顾往期 不要再说不会Spring了!Spring第一天,学会进大厂! Spring第二天,你必须知道容器注册组件的几种方式!学废它吊打面试官! 今天讲解Spring中Bean的生命周期. ...
- 1. spring5源码 -- Spring整体脉络 IOC加载过程 Bean的生命周期
可以学习到什么? 0. spring整体脉络 1. 描述BeanFactory 2. BeanFactory和ApplicationContext的区别 3. 简述SpringIoC的加载过程 4. ...
- spring in action 学习笔记四:bean的生命周期
bean 的生命周期分为:一个是ApplicationContext的容器的bean的生命周期,另一个是BeanFactory容器的生命周期. 首先介绍一下:ApplicationContext的容器 ...
- 在Spring Bean的生命周期中各方法的执行顺序
Spring 容器中的 Bean 是有生命周期的,Spring 允许在 Bean 在初始化完成后以及 Bean 销毁前执行特定的操作,常用的设定方式有以下十种: 通过实现 InitializingBe ...
- 【spring源码系列】之【Bean的生命周期】
为源码付出的每一分努力都不会白费. 1. Bean的实例化概述 前一篇分析了BeanDefinition的封装过程,最终将beanName与BeanDefinition以一对一映射关系放到beanDe ...
- Java框架spring 学习笔记(三):Bean 的生命周期
当一个 bean 被实例化时,它可能需要执行一些初始化使它转换成可用状态.当bean不再需要,并且从容器中移除时,需要做一些清除工作.为了定义安装和拆卸一个 bean,我们只要声明init-metho ...
- Spring官网阅读(十)Spring中Bean的生命周期(下)
文章目录 生命周期概念补充 实例化 createBean流程分析 doCreateBean流程分析 第一步:factoryBeanInstanceCache什么时候不为空? 第二步:创建对象(crea ...
随机推荐
- Java实现 LeetCode 13 罗马数字转整数
13. 罗马数字转整数 罗马数字包含以下七种字符: I, V, X, L,C,D 和 M. 字符 数值 I 1 V 5 X 10 L 50 C 100 D 500 M 1000 例如, 罗马数字 2 ...
- Android getMeasuredHeight()与getHeight()的区别
getMeasuredHeight()返回的是原始测量高度,与屏幕无关 getHeight()返回的是在屏幕上显示的高度 实际上在当屏幕可以包裹内容的时候,他们的值是相等的,只有当view超出屏幕后, ...
- 【Spring注解驱动开发】使用@Scope注解设置组件的作用域
写在前面 Spring容器中的组件默认是单例的,在Spring启动时就会实例化并初始化这些对象,将其放到Spring容器中,之后,每次获取对象时,直接从Spring容器中获取,而不再创建对象.如果每次 ...
- 搭建手机web服务器-----内网穿透(无需Root)
搭建手机web服务器-----内网穿透(无需Root) 一.内网穿透部分 前言: 网上内网穿透的方法很多,像花生壳.Ngrok.Frp等等,但是大多都需要获取手机root权限 本文使用的软件是Term ...
- 源码分析 | 手写mybait-spring核心功能(干货好文一次学会工厂bean、类代理、bean注册的使用)
作者:小傅哥 博客:https://bugstack.cn - 汇总系列原创专题文章 沉淀.分享.成长,让自己和他人都能有所收获! 一.前言介绍 一个知识点的学习过程基本分为:运行helloworld ...
- JS 姓氏,区域,消息组成的随机内容定时随机展示
var surname_g = "\u8D75\u94B1\u5B59\u674E\u5468\u5434\u90D1\u738B\u51AF\u9648\u891A\u536B\u848B ...
- 总结:修改相关postgres用户密码
1.修改linux系统postgres用户的密码 PostgreSQL会创建一个默认的linux用户postgres,修改该用户密码的方法如下: 步骤一:删除用户postgres的密码 sudo p ...
- 【转载】图解NumPy
目录 1. 读写文件 2. 内建向量/矩阵 3. 切片操作 4. 聚合函数 4.1. 向量 4.2. 矩阵 5. 矩阵的转置和重构 6. 常用操作API 7. 应用实例 7.1. 生成向量.矩阵 7. ...
- [每日一题2020.06.15]P1226 【模板】快速幂取余运算
我是题目 快速幂就是快速求 \(a^b\)的一种算法 快速幂 思想 : 比如我要求 \(6^9\) 首先将幂转化为二进制形式 : \[6^9 = 6^{1001} \tag{1} \] 可以得到 : ...
- Python中的字段分割
很多时候我们要完成分词的任务,这篇文章讲的非常非常好.生动形象,原文是https://www.cnblogs.com/douzi2/p/5579651.html,作者是宋桓公.