Spring Ioc源码分析 之 Bean的加载(7):初始化
接着分析doCreateBean()的第6步——初始化 bean 实例对象
首先回顾下CreateBean的主流程:
- 如果是单例模式,从factoryBeanInstanceCache 缓存中获取BeanWrapper 实例对象并删除缓存
- 调用 createBeanInstance() 实例化 bean
- 后置处理
- 单例模式的循环依赖处理
- 属性填充
- 初始化 bean 实例对象
- 依赖检查
- 注册bean的销毁方法
一、初始化
Spring在对Bean进行属性填充之后,会对Bean进行初始化,代码如下:
//AbstractAutowireCapableBeanFactory.javaprotected Object initializeBean(final String beanName, final Object bean, @Nullable RootBeanDefinition mbd) {//JDK的安全机制验证权限if (System.getSecurityManager() != null) {// <1> 激活 Aware 方法,对特殊的 bean 处理:Aware、BeanClassLoaderAware、BeanFactoryAwareAccessController.doPrivileged((PrivilegedAction<Object>) () -> {invokeAwareMethods(beanName, bean);return null;}, getAccessControlContext());}else {// <1> 激活 Aware 方法,对特殊的 bean 处理:Aware、BeanClassLoaderAware、BeanFactoryAwareinvokeAwareMethods(beanName, bean);}Object wrappedBean = bean;// <2> 后置处理器,beforeif (mbd == null || !mbd.isSynthetic()) {wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);}// <3> 激活用户自定义的 init 方法try {invokeInitMethods(beanName, wrappedBean, mbd);}catch (Throwable ex) {throw new BeanCreationException((mbd != null ? mbd.getResourceDescription() : null),beanName, "Invocation of init method failed", ex);}// <2> 后置处理器,afterif (mbd == null || !mbd.isSynthetic()) {wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);}return wrappedBean;}
初始化 bean 的方法其实就是三个步骤的处理,而这三个步骤主要还是根据用户设定的来进行初始化,这三个过程为:
- <1> 激活 Aware 方法。
- <2> 后置处理器。
- <3> 自定义的 init 方法。
- 1.1、Aware
Aware ,英文翻译是意识到的,感知的。Spring 提供了诸多 Aware 接口,用于辅助 Spring Bean 以编程的方式调用 Spring 容器,通过实现这些接口,可以增强 Spring Bean 的功能。
Spring 提供了如下系列的 Aware 接口:
- LoadTimeWeaverAware:加载Spring Bean时织入第三方模块,如AspectJ
- BeanClassLoaderAware:加载Spring Bean的类加载器
- BootstrapContextAware:资源适配器BootstrapContext,如JCA,CCI
- ResourceLoaderAware:底层访问资源的加载器
- BeanFactoryAware:声明BeanFactory
- PortletConfigAware:PortletConfig
- PortletContextAware:PortletContext
- ServletConfigAware:ServletConfig
- ServletContextAware:ServletContext
- MessageSourceAware:国际化
- ApplicationEventPublisherAware:应用事件
- NotificationPublisherAware:JMX通知
- BeanNameAware:声明Spring Bean的名字
- 1.2、后置处理器
BeanPostProcessor
在前面介绍 bean 加载的过程曾多次遇到,
它的作用是:
如果我们想要在 Spring 容器完成 Bean 的实例化,配置和其他的初始化后添加一些自己的逻辑处理,那么请使用该接口
,这个接口给与了用户充足的权限去更改或者扩展 Spring,是我们对 Spring 进行扩展和增强处理一个必不可少的接口。
applyBeanPostProcessorsBeforeInitialization()
方法,代码如下:
// AbstractAutowireCapableBeanFactory.java@Override
public Object applyBeanPostProcessorsBeforeInitialization(Object existingBean, String beanName)throws BeansException {Object result = existingBean;// 遍历 BeanPostProcessor 数组for (BeanPostProcessor processor : getBeanPostProcessors()) {// 处理Object current = processor.postProcessBeforeInitialization(result, beanName);// 返回空,则返回 resultif (current == null) {return result;}// 修改 resultresult = current;}return result;
}
applyBeanPostProcessorsAfterInitialization()
方法,代码如下:
// AbstractAutowireCapableBeanFactory.java
@Override
public Object applyBeanPostProcessorsAfterInitialization(Object existingBean, String beanName)throws BeansException {Object result = existingBean;// 遍历 BeanPostProcessorfor (BeanPostProcessor processor : getBeanPostProcessors()) {// 处理Object current = processor.postProcessAfterInitialization(result, beanName);// 返回空,则返回 resultif (current == null) {return result;}// 修改 resultresult = current;}return result;
}
其逻辑就是通过 getBeanPostProcessors() 方法,获取定义的 BeanPostProcessor ,然后分别调用其 postProcessBeforeInitialization() 和 postProcessAfterInitialization() 方法,进行自定义的业务处理。
- 1.3、自定义init方法
在xml中有一个< bean >标签的配置,init-method
方法,是可以让我们在Bean初始化的时候,先执行我们自定义的一些逻辑。
其实就是在这里被触发的,代码如下:
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.isTraceEnabled()) {logger.trace("Invoking afterPropertiesSet() on bean with name '" + beanName + "'");}if (System.getSecurityManager() != null) { // 安全模式try {AccessController.doPrivileged((PrivilegedExceptionAction<Object>) () -> {// <1> 属性初始化的处理((InitializingBean) bean).afterPropertiesSet();return null;}, getAccessControlContext());} catch (PrivilegedActionException pae) {throw pae.getException();}} else {// <1> 属性初始化的处理((InitializingBean) bean).afterPropertiesSet();}}if (mbd != null && bean.getClass() != NullBean.class) {String initMethodName = mbd.getInitMethodName();if (StringUtils.hasLength(initMethodName) &&!(isInitializingBean && "afterPropertiesSet".equals(initMethodName)) &&!mbd.isExternallyManagedInitMethod(initMethodName)) {// <2> 激活用户自定义的初始化方法invokeCustomInitMethod(beanName, bean, mbd);}}
}
首先,检查是否为 InitializingBean
。如果是的话,需要执行 afterPropertiesSet()
方法,因为我们除了可以使用 init-method 来自定初始化方法外,还可以实现 InitializingBean 接口。接口仅有一个 afterPropertiesSet() 方法。
两者的执行先后顺序是先 :<1> 的 #afterPropertiesSet() 方法
后 <2> 的 init-method 对应的方法。
本文转自:https://cloud.tencent.com/developer/article/1521203
Spring Ioc源码分析 之 Bean的加载(7):初始化相关推荐
- Spring Ioc源码分析 之 Bean的加载(6):属性填充(populateBean())
"属性填充",也是在populateBean()方法中. 首先回顾下CreateBean的主流程: 如果是单例模式,从factoryBeanInstanceCache 缓存中获取B ...
- Spring Ioc源码分析 之 Bean的加载(4):实例化Bean(createBeanInstance()方法)
实例化 Bean 在doCreateBean()代码 <2> 处,有一行代码instanceWrapper = createBeanInstance(beanName, mbd, args ...
- Spring Ioc源码分析 之 Bean的加载(5):循环依赖处理(populateBean())
首先回顾下Bean加载的主流程: 1.如果是单例模式,从factoryBeanInstanceCache 缓存中获取BeanWrapper 实例对象并删除缓存 2.调用 createBeanInsta ...
- Spring Ioc 源码分析(一)--Spring Ioc容器的加载
1.目标:熟练使用spring,并分析其源码,了解其中的思想.这篇主要介绍spring ioc 容器的加载 2.前提条件:会使用debug 3.源码分析方法:Intellj idea debug 模式 ...
- java获取当前周一_Java互联网架构-Spring IOC源码分析
欢迎关注头条号:java小马哥 周一至周日下午三点半!精品技术文章准时送上!!! 精品学习资料获取通道,参见文末 源码介绍之前,看几个问题: Bean的承载对象是什么? Bean的定义如何存储的? B ...
- Spring Ioc 源码分析(一)- XML 解析
2019独角兽企业重金招聘Python工程师标准>>> 注 :源码对应版本为 4.2.8.RELEASE 引入Spring依赖的时候,是否发现spring依赖有spring-bean ...
- Myabtis源码分析五-Mybatis配置加载完全图解,建造者模式的使用,涵盖Java各种技术栈
private SqlSessionFactory sqlSessionFactory; @Before public void init() throws IOException { //----- ...
- nhibernate源码分析之六: Criteria数据加载
ICriteria是使用Expression进行数据加载的接口, 提供了设置表达式(Expression), 排序方式(Order), 分页记录等操作. 它使用一种类似于SQL语句where表达表的方 ...
- MPF源码分析之资源文件加载
本文将分析MPF客户端框架中资源文件相关的源代码,以github包中提供的qq界面demo作为 起点,一步一步分析程序的运行原理: 主程序很简单,代码如下: int APIENTRY _tWinMai ...
最新文章
- 数学知识--Methods for Non-Linear Least Squares Problems(第二章)
- 无毛刺的时钟切换电路(Glitch-free clock switching circuit)设计(Verilog)
- wegame饥荒一直连接中_怪诞画风下的异世界生存,一款让你吃到撑的游戏——《饥荒》...
- SAP Spartacus Page Layout - 页面布局设计
- struct sockaddr_nl 结构体 由来、含义以及使用——获取Linux路由表
- [react] React为什么不要直接修改state?如果想修改怎么做?
- 200 行代码实现一个滑动验证码
- 预处理器loader总结
- Java进阶:GIT
- jQuery计算时间差和阴阳历转换
- 搭建一个misskey实例
- 微信小程序自定义switch中带文字效果
- 行测-图形推理-7-相异图形类
- linux技术基础教程 [转载]
- pdksh-5.2.14-36.el5.i386.rpm
- 没有可用软件包。错误:无须任何处理
- debian更新apt源报错 ...is not valid yet (invalid for another 722d 21h 13min 35s).
- 把excel转换成html格式的文件,极强PDF转换器将Excel表格转换成HTML网页格式的方法...
- COI 2020 Semafor(矩阵乘法+优化)
- 【时间序列】001-推断统计