Spring源码之bean的初始化initializeBean方法解读
目录
- 前言
- `initializeBean()` 方法概览
- `initializeBean()` 方法详解
- `invokeAwareMethods()` 方法
- `applyBeanPostProcessorsBeforeInitialization()` 方法(重点)
- `invokeInitMethods()` 方法(重点)
- `applyBeanPostProcessorsAfterInitialization()` 方法(重点)
- `spring` 中初始化 `bean` 的方式
- 使用 `@PostConstruct` 注解
- 实现 `InitializingBean` 接口
- 使用 `@Bean` 注解
- 执行顺序
前言
这篇文章是 IOC
容器初始化启动时,抽象类 AbstractAutowireCapableBeanFactory
的 doCreateBean()
方法里面的 initializeBean()
方法,它是进行 bean
的初始化的方法
阅读本篇文章,同时可以参考阅读 spring源码之getBean(获取 bean)方法解读(二) 和 Spring Aop代理对象的产生(一) 这两篇文章的 doCreateBean()
方法
initializeBean()
方法概览
到此时,bean
已完成了如下两个重要工作
- 调用
createBeanInstance()
方法:完成bean
的实例化工作 - 调用
populateBean()
方法:完成bean
的属性填充注入工作
protected Object initializeBean(final String beanName, final Object bean, @Nullable RootBeanDefinition mbd) {// 对特殊的bean进行处理:实现了 Aware、BeanClassLoaderAware、BeanFactoryAware 的处理if (System.getSecurityManager() != null) {AccessController.doPrivileged((PrivilegedAction<Object>) () -> {// 激活 Aware 方法invokeAwareMethods(beanName, bean);return null;}, getAccessControlContext());}else {invokeAwareMethods(beanName, bean);}Object wrappedBean = bean;if (mbd == null || !mbd.isSynthetic()) {// 调用了bean后处理器的方法// BeanPostProcessor 提供的方法,在bean初始化前调用,这时的 bean已完成了实例化和属性填充注入工作wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);}try {// 激活自定义的init的方法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()) {// 调用bean后处理器的方法// BeanPostProcessor 提供的方法,在bean初始化后调用,这时候的bean 已经创建完成了wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);}return wrappedBean;
}
- 对实现了
Aware
接口的bean
进行相关设置 - 调用
bean
后处理器的方法applyBeanPostProcessorsBeforeInitialization()
- 执行实现了
InitializingBean
或者用户自定义的init
方法方法 - 调用
bean
后处理器的方法applyBeanPostProcessorsAfterInitialization()
:此处可以产生aop
的代理对象
initializeBean()
方法详解
invokeAwareMethods()
方法
实现 Aware
接口用于让 bean
能拥有某些额外的感知能力
- 如果
bean
实现了BeanNameAware
接口,则将beanName
设置进去 - 如果
bean
实现了BeanClassLoaderAware
接口,则将ClassLoader
设置进去 - 如果
bean
实现了BeanFactoryAware
接口,则将beanFactory
设置进去
private void invokeAwareMethods(final String beanName, final Object bean) {if (bean instanceof Aware) {if (bean instanceof BeanNameAware) {((BeanNameAware) bean).setBeanName(beanName);}if (bean instanceof BeanClassLoaderAware) {ClassLoader bcl = getBeanClassLoader();if (bcl != null) {((BeanClassLoaderAware) bean).setBeanClassLoader(bcl);}}if (bean instanceof BeanFactoryAware) {((BeanFactoryAware) bean).setBeanFactory(AbstractAutowireCapableBeanFactory.this);}}
}
applyBeanPostProcessorsBeforeInitialization()
方法(重点)
@Override
public Object applyBeanPostProcessorsBeforeInitialization(Object existingBean, String beanName)throws BeansException {Object result = existingBean;// 获取所有实现了 BeanPostProcessors 接口的类,进行遍历for (BeanPostProcessor beanProcessor : getBeanPostProcessors()) {// 核心方法:postProcessBeforeInitialization()Object current = beanProcessor.postProcessBeforeInitialization(result, beanName);if (current == null) {return result;}result = current;}return result;
}
postProcessBeforeInitialization()
方法是 BeanPostProcessor
接口提供的方法,可以看到它是在 bean
初始化之前调用的,这时的 bean
已完成了实例化和属性填充注入工作
public interface BeanPostProcessor {@Nullabledefault Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {return bean;}@Nullabledefault Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {return bean;}
}
postProcessBeforeInitialization()
:在bean
初始化之前调用,可以改变bean
的一些属性postProcessAfterInitialization()
:在bean
初始化之后调用,可以改变bean
的一些属性
关于 BeanPostProcessor
接口的详解可以查看:https://blog.csdn.net/qq_36882793/article/details/106040809
关于 BeanPostProcessor
接口的详细使用可以查看:https://blog.csdn.net/mamamalululu00000000/article/details/106547490
invokeInitMethods()
方法(重点)
bean
的初始化方式除了可以使用 init-method
属性或 @Bean(initMethod=''”)
,还可以通过实现 InitializingBean
接口,并且在 afterPropertiesSet()
方法中实现自己初始化的业务逻辑
调用顺序则是 afterPropertiesSet()
先调用,后面调用 init-method
指定的方法
protected void invokeInitMethods(String beanName, final Object bean, @Nullable RootBeanDefinition mbd)throws Throwable {// 首先检查是否是InitializingBean,如果是的话则需要调用 afterPropertiesSet 方法boolean isInitializingBean = (bean instanceof InitializingBean);if (isInitializingBean && (mbd == null || !mbd.isExternallyManagedInitMethod("afterPropertiesSet"))) {if (logger.isDebugEnabled()) {logger.debug("Invoking afterPropertiesSet() on bean with name '" + beanName + "'");}// 调用 afterPropertiesSet 方法if (System.getSecurityManager() != null) {try {AccessController.doPrivileged((PrivilegedExceptionAction<Object>) () -> {((InitializingBean) bean).afterPropertiesSet();return null;}, getAccessControlContext());}catch (PrivilegedActionException pae) {throw pae.getException();}}else {((InitializingBean) bean).afterPropertiesSet();}}if (mbd != null && bean.getClass() != NullBean.class) {// 从RootBeanDefinition 中获取initMethod 方法名称String initMethodName = mbd.getInitMethodName();// 调用initMethod 方法if (StringUtils.hasLength(initMethodName) &&!(isInitializingBean && "afterPropertiesSet".equals(initMethodName)) &&!mbd.isExternallyManagedInitMethod(initMethodName)) {invokeCustomInitMethod(beanName, bean, mbd);}}
}
applyBeanPostProcessorsAfterInitialization()
方法(重点)
@Override
public Object applyBeanPostProcessorsAfterInitialization(Object existingBean, String beanName)throws BeansException {Object result = existingBean;// 获取所有实现了 BeanPostProcessors 接口的类,进行遍历for (BeanPostProcessor beanProcessor : getBeanPostProcessors()) {// 核心方法:postProcessAfterInitialization()Object current = beanProcessor.postProcessAfterInitialization(result, beanName);if (current == null) {return result;}result = current;}return result;
}
postProcessAfterInitialization()
方法是 BeanPostProcessor
接口提供的方法,可以看到它是在 bean
初始化之后调用的,这时的 bean
已完成了实例化,属性填充注入,初始化的工作;可以认为是一个完整的 bean
已在 spring
容器中了
如果使用了 spring aop
功能,那么代理对象的产生就在这个 applyBeanPostProcessorsAfterInitialization()
方法中。注意产生代理对象的时机
- 是在
bean
的实例化createBeanInstance()
方法,属性填充注入populateBean()
方法之后的initializeBean()
初始化方法中产生的 - 在
initializeBean()
方法中的applyBeanPostProcessorsAfterInitialization()
方法具体产生
spring
中初始化 bean
的方式
xml
配置文件中指定init-method
标签- 使用
@PostConstruct
注解 - 实现
InitializingBean
接口 - 使用
@Bean
注解
使用 @PostConstruct
注解
@Service
public class AService {@PostConstructpublic void init() {System.out.println("===初始化===");}
}
实现 InitializingBean
接口
@Service
public class BService implements InitializingBean {@Overridepublic void afterPropertiesSet() throws Exception {System.out.println("===初始化===");}
}
使用 @Bean
注解
使用 initMethod()
可以指定初始化方法
@Target({ElementType.METHOD, ElementType.ANNOTATION_TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Bean {@AliasFor("name")String[] value() default {};@AliasFor("value")String[] name() default {};Autowire autowire() default Autowire.NO;String initMethod() default "";String destroyMethod() default AbstractBeanDefinition.INFER_METHOD;
}
执行顺序
具体的执行顺序可以查看 initializeBean()
源码
Spring源码之bean的初始化initializeBean方法解读相关推荐
- Spring-bean的循环依赖以及解决方式___Spring源码初探--Bean的初始化-循环依赖的解决
本文主要是分析Spring bean的循环依赖,以及Spring的解决方式. 通过这种解决方式,我们可以应用在我们实际开发项目中. 什么是循环依赖? 怎么检测循环依赖 Spring怎么解决循环依赖 S ...
- Spring源码解析-bean实例化
Spring源码解析-bean实例化 本文介绍Spring创建 bean 过程中的第一个步骤:实例化 bean. 1. Bean实例化源码 虽然实例化Bean有多种方式(包括静态工厂和工厂实例 ...
- Spring 源码解析 - Bean创建过程 以及 解决循环依赖
一.Spring Bean创建过程以及循环依赖 上篇文章对 Spring Bean资源的加载注册过程进行了源码梳理和解析,我们可以得到结论,资源文件中的 bean 定义信息,被组装成了 BeanDef ...
- Spring源码深度解析,Spring源码以及Bean的生命周期(五)(附代码示例:)
五)Bean 的生命周期,创建---初始化---销毁的过程 目录 五)Bean 的生命周期,创建---初始化---销毁的过程 一 , 指定初始化方法 init-method 方法 二 ,指定销毁 ...
- Spring源码剖析——Bean的配置与启动
IOC介绍 相信大多数人在学习Spring时 IOC 和 Bean 算得上是最常听到的两个名词,IOC在学习Spring当中出现频率如此之高必然有其原因.如果我们做一个比喻的话,把Bean说成Sp ...
- Spring源码之Bean的注册(使用XML配置的方式)
本文分析的Spring源码是5.2.2版本,使用Gradle进行管理. 一.Bean的注册,先来看通过XML配置Bean的方式 1.配置applicationContext.xml: <?xml ...
- 一、如何阅读Spring源码(全网最简单的方法)
学习Java最好最有效的方法是学习Spring,但是最笨最没效的方法也是学习Spring. 为什么这么说呢?道理其实很简单 A.Spring很庞大,很完善,也非常的底层,如果我们学会的Spring,那 ...
- Spring源码分析——Bean的生命周期
文章目录 说明 测试代码 说明 本文从源码的角度分析Spring中Bean的加载过程,本文使用的Spring版本为4.3.25.RELEASE 测试代码 测试代码如下,根据这段简单的测试代码,一步步跟 ...
- Spring源码之Bean的注册(注解方式)
1.创建AnnotationConfigApplicationContext AnnotationConfigApplicationContext context = new AnnotationCo ...
- 三 spring源码解析--- Bean解析接口结构分析
2019独角兽企业重金招聘Python工程师标准>>> 解析Bean是通过定义抽象的bean reader来解析,结构图如下 1.AbstractBeanDefinitionRead ...
最新文章
- 百信银行基于 Apache Hudi 实时数据湖演进方案
- Kotlin入门简介
- 方程组的直接解法和迭代法 python_最小二乘法及python 实现
- 微信授权 php josn,php怎么获取微信多客服json数据
- 42岁失业,有150万存款,房子无贷款,不想上班做点什么好?
- (Windows7)Visual Studio 2017编译运行出现脚本错误的解决方法
- Ubuntu 安装mujoco
- PPT计算机辅助教学,计算机辅助教学与多媒体课件制作
- T-SQL 基础简介
- python列表姓氏_Python 批量生成中文姓名(百家姓)
- pixi 小游戏_学习如何用pixi.js开发微信小游戏
- python生成摸头GIF动态图
- 练习二:工作日天气预报
- Unit3D打包android时出错 CommandInvokationFailure: Unable to list target platforms. Please make sure the a
- Hive基础知识及底层架构
- app 的 icon图标 有黑边
- 盘点系列:一度大热的TWS耳机今年表现如何?
- 惠州学院计算机学院2019,2019惠州学院专业排名
- 计算机桌面打标签,桌面记事本,详细教您怎么在桌面添加便签
- matlab求解代数等式,2008-2009学年线性代数试卷A及答案
热门文章
- 自动驾驶 11-2: 激光雷达传感器模型和点云 LIDAR Sensor Models and Point Clouds
- 算法:求树的最大深度104. Maximum Depth of Binary Tree
- AWS SageMaker 基于 XGBoost 的用户流失预测
- linux内核代码入口地址,Linux内核源代码分析——Linux内核的入口
- 新浪推荐 二面 移动零
- 第五章平稳过程(1)
- 怎么回滚版本_Win 10 暂停更新及回滚方法
- vofuria的开发(3)将vuforia引入新建立的工程
- css中margin标记可以带一个、二个、三个、四个参数,各有不同的含义
- 【2019 NWERC - D 】Disposable Switches【最短路、单调栈、数学思维】