【spring源码系列】之【Bean的初始化】
只要不放弃,希望迟早都会到来!
1. Bean的初始化
如果把bean的生命周期看作一个婴儿诞生过程的,那么创建实例相当于婴儿从母体出来,一丝不挂光秃秃;属性赋值相当于给宝宝的头带帽子,上身穿衣服、下神穿裤子、还有脚丫穿袜子;而初始化相当于教宝宝一些常规的动作,比如给宝宝吸奶,打嗝拍打,哄睡觉等,本篇继续分析初始化源码。
2. 初始化流程概览
3. 源码分析
进入initializeBean
方法:
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()) {
// 初始化前处理的beanPostProcessor , 比如aware接口,InitDestroyBeanPostProcessor,
// ImportAwareBeanPostPorcessor 对ImportAware的支持
wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
}
try {
// 激活 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()) {
// 初始化后处理的beanPostProcessor
wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
}
return wrappedBean;
}
看到流程中主要分为上述流程概览中所述的四个步骤:
step1
:激活aware接口;
step2
:初始化前处理的beanPostProcessor;
step3
:激活 init-method方法;
step4
:初始化后处理的beanPostProcessor.
下面逐一分析。
激活aware接口,源码如下:
private void invokeAwareMethods(String beanName, 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);
}
}
}
分别对BeanNameAware、BeanClassLoaderAware、BeanFactoryAwareaware接口进行处理,设置对应的属性;接下来进入applyBeanPostProcessorsBeforeInitialization
方法:
public Object applyBeanPostProcessorsBeforeInitialization(Object existingBean, String beanName)
throws BeansException {
Object result = existingBean;
for (BeanPostProcessor processor : getBeanPostProcessors()) {
Object current = processor.postProcessBeforeInitialization(result, beanName);
if (current == null) {
return result;
}
result = current;
}
return result;
}
该方法对初始化前的beanPostProcessor进行处理,对比如InitDestroyBeanPostProcessor,对@PostConstruct的支持, ApplicationContextAwareProcessor对某个Aware接口方法的调用,ImportAwareBeanPostPorcessor对ImportAware的支持等;
接下来InitializingBean接口和init-method 属性调用对应方法为invokeInitMethods:
protected void invokeInitMethods(String beanName, Object bean, @Nullable RootBeanDefinition mbd)
throws Throwable {
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>) () -> {
((InitializingBean) bean).afterPropertiesSet();
return null;
}, getAccessControlContext());
}
catch (PrivilegedActionException pae) {
throw pae.getException();
}
}
else {
// 调用afterPropertiesSet方法
((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)) {
// 调用自定义的init方法
invokeCustomInitMethod(beanName, bean, mbd);
}
}
}
afterPropertiesSet 和 Init-method 和有@PostConstruct 注解的方法其实核心功能都是一样的,只是调用时序不一样而已,都是在该类实例化和 IOC 做完后调用的,我们可以在这些方法中做一些在 spring 或者 servlet 容器启动的时候的初始化工作。比如缓存预热,比如缓存数据加载到内存,比如配置解析,等等初始化工作调用顺序为先调用@PostConstruct(注解使用)、然后是 afterPropertiesSet、InitMethod(xml 配置)方法。
最后一步,初始化后处理的beanPostProcessor,这里最主要的是完成代理的生成,该内容放到后面AOP阶段再深入。
4. 总结
本篇主要分析了bean的初始化相关操作,包括@PostConstruct注解的支持,Aware接口的支持,以及初始化后的afterPropertiesSet方法以及InitMethod方法的支持,最后完成BeanPostProcessor的后置处理,生成aop代理实例,后续将继续分析FactoryBean接口实例化对象的过程。
【spring源码系列】之【Bean的初始化】的更多相关文章
- Spring源码系列(二)--bean组件的源码分析
简介 spring-bean 组件是 Spring IoC 的核心,我们可以使用它的 beanFactory 来获取所需的对象,对象的实例化.属性装配和初始化等都可以交给 spring 来管理. 本文 ...
- Spring源码系列(三)--spring-aop的基础组件、架构和使用
简介 前面已经讲完 spring-bean( 详见Spring ),这篇博客开始攻克 Spring 的另一个重要模块--spring-aop. spring-aop 可以实现动态代理(底层是使用 JD ...
- Spring源码系列(四)--spring-aop是如何设计的
简介 spring-aop 用于生成动态代理类(底层是使用 JDK 动态代理或 cglib 来生成代理类),搭配 spring-bean 一起使用,可以使 AOP 更加解耦.方便.在实际项目中,spr ...
- Spring源码系列 — Bean生命周期
前言 上篇文章中介绍了Spring容器的扩展点,这个是在Bean的创建过程之前执行的逻辑.承接扩展点之后,就是Spring容器的另一个核心:Bean的生命周期过程.这个生命周期过程大致经历了一下的几个 ...
- 事件机制-Spring 源码系列(4)
事件机制-Spring 源码系列(4) 目录: Ioc容器beanDefinition-Spring 源码(1) Ioc容器依赖注入-Spring 源码(2) Ioc容器BeanPostProcess ...
- Ioc容器BeanPostProcessor-Spring 源码系列(3)
Ioc容器BeanPostProcessor-Spring 源码系列(3) 目录: Ioc容器beanDefinition-Spring 源码(1) Ioc容器依赖注入-Spring 源码(2) Io ...
- Ioc容器beanDefinition-Spring 源码系列(1)
Ioc容器beanDefinition-Spring 源码系列(1) 目录: Ioc容器beanDefinition-Spring 源码(1) Ioc容器依赖注入-Spring 源码(2) Ioc容器 ...
- Spring源码系列 — 注解原理
前言 前文中主要介绍了Spring中处理BeanDefinition的扩展点,其中着重介绍BeanDefinitionParser方式的扩展.本篇文章承接该内容,详解Spring中如何利用BeanDe ...
- Spring源码系列 — BeanDefinition扩展点
前言 前文介绍了Spring Bean的生命周期,也算是XML IOC系列的完结.但是Spring的博大精深,还有很多盲点需要摸索.整合前面的系列文章,从Resource到BeanDefinition ...
- Spring源码系列 — BeanDefinition
一.前言 回顾 在Spring源码系列第二篇中介绍了Environment组件,后续又介绍Spring中Resource的抽象,但是对于上下文的启动过程详解并未继续.经过一个星期的准备,梳理了Spri ...
随机推荐
- IDEA 最实用快捷键【MAC版本】
目录 option + F7 Ctrl + B / Ctrl +鼠标左键(一键两用,可以无限循环的跳过来跳过去,我跳过去了,我又跳回去了) command + E (这个快捷键很有用,为什么我老是用不 ...
- python实现发送微信消息
import json from threading import Timer from wxpy import * import requests import urllib.parse def g ...
- BERT模型的OneFlow实现
BERT模型的OneFlow实现 模型概述 BERT(Bidirectional Encoder Representations from Transformers)是NLP领域的一种预训练模型.本案 ...
- 我进金山wps啦!
成功进入金山wps暑期精英训练营,希望能够学到很多知识,写这篇文章纪念一下
- 剑指 Offer 06. 从尾到头打印链表
链接:https://leetcode-cn.com/problems/cong-wei-dao-tou-da-yin-lian-biao-lcof/ 标签:链表 题目 输入一个链表的头节点,从尾到头 ...
- P1123 取数游戏
题目描述 一个N \times MN×M的由非负整数构成的数字矩阵,你需要在其中取出若干个数字,使得取出的任意两个数字不相邻(若一个数字在另外一个数字相邻88个格子中的一个即认为这两个数字相邻),求取 ...
- day20200911
UG12.0进入运动仿真模块 新建仿真 定义固定连杆 定义其他连杆 定义运动副 定义驱动 定义解算方案并求解 导出动画
- H5播放需要解密的m3u8音频文件
<audio ref="audio"></audio> import CryptoJS from "crypto-js"; import ...
- 把axios获取到的数据渲染到列表上,使用better-scroll实现列表左右滑动
问题:axios数据请求完后,页面是有数据的,即页面看到有数据,但是better-scroll却无法滚动 原因:这是因为在数据更新前,better-scroll已经渲染完成了 解决方法:这是个异步问题 ...
- YOLO V4的模型训练
1.YOLO V4模型训练的基本思路 所有机器学习涉及模型训练,一般都有训练集.验证集.测试集,因此需要准备数据集.有了数据集,再调用训练的算法,获取训练的结果.v3.v4模型训练方法相同. 2.YO ...