Spring IoC Container源码分析(二)-bean初始化流程
准备
Person实例
@Data
public class Person {
private String name;
private int age;
}
xml bean配置
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd">
<bean id="person" class="com.gcdd1993.spring.framework.base.domain.Person"/>
</beans>
入口
AbstractApplicationContext applicationContext = new ClassPathXmlApplicationContext("config.xml");
applicationContext.getBean("person");
使用Debug进入ClassPathXmlApplicationContext构造函数,源码如下
public ClassPathXmlApplicationContext(String[] configLocations, boolean refresh, ApplicationContext parent)
throws BeansException {
super(parent);
setConfigLocations(configLocations);
if (refresh) {
refresh();
}
}
super(parent)
一步步向上调用父类构造函数,路径为
ClassPathXmlApplicationContext -> AbstractXmlApplicationContext -> AbstractRefreshableConfigApplicationContext -> AbstractRefreshableApplicationContext -> AbstractApplicationContext
历经整个继承体系,最终到达AbstractApplicationContext:
public AbstractApplicationContext(ApplicationContext parent) {
this();
setParent(parent);
}
最后会设置当前ApplicationContext的父级ApplicationContext
setConfigLocations(configLocations)
设置配置文件路径,解析的细节参照官方文档Resource一节,不是本文讨论的重点,在此略过。
public void setConfigLocations(String... locations) {
if (locations != null) {
Assert.noNullElements(locations, "Config locations must not be null");
this.configLocations = new String[locations.length];
for (int i = 0; i < locations.length; i++) {
this.configLocations[i] = resolvePath(locations[i]).trim();
}
}
else {
this.configLocations = null;
}
}
refresh()
此方法是Spring容器的核心方法,源码(精简了try catch部分)如下:
public void refresh() throws BeansException, IllegalStateException {
// Prepare this context for refreshing.
prepareRefresh();
// Tell the subclass to refresh the internal bean factory.
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
// Prepare the bean factory for use in this context.
prepareBeanFactory(beanFactory);
// Allows post-processing of the bean factory in context subclasses.
postProcessBeanFactory(beanFactory);
// Invoke factory processors registered as beans in the context.
invokeBeanFactoryPostProcessors(beanFactory);
// Register bean processors that intercept bean creation.
registerBeanPostProcessors(beanFactory);
// Initialize message source for this context.
initMessageSource();
// Initialize event multicaster for this context.
initApplicationEventMulticaster();
// Initialize other special beans in specific context subclasses.
onRefresh();
// Check for listener beans and register them.
registerListeners();
// Instantiate all remaining (non-lazy-init) singletons.
finishBeanFactoryInitialization(beanFactory);
// Last step: publish corresponding event.
finishRefresh();
}
此处可以看到Spring编码方式近似于流程图的,重点部分都抽出为了单独的方法,流程清晰,易于理解。我们一步步看:
prepareRefresh()
上下文刷新前预热
protected void prepareRefresh() {
this.startupDate = System.currentTimeMillis();
this.closed.set(false);
this.active.set(true);
if (logger.isInfoEnabled()) {
logger.info("Refreshing " + this);
}
// Initialize any placeholder property sources in the context environment
initPropertySources();
// Validate that all properties marked as required are resolvable
// see ConfigurablePropertyResolver#setRequiredProperties
getEnvironment().validateRequiredProperties();
// Allow for the collection of early ApplicationEvents,
// to be published once the multicaster is available...
this.earlyApplicationEvents = new LinkedHashSet<ApplicationEvent>();
}
- 设置上下文基本信息,如startupDate(启动时刻)、closed(是否关闭)、active(是否存活)等等。
- 解析占位符资源,并验证标记为required的资源是否可用
obtainFreshBeanFactory()
初始化beanFactory(bean工厂,实际存放bean的就是它了)
protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {
refreshBeanFactory();
ConfigurableListableBeanFactory beanFactory = getBeanFactory();
if (logger.isDebugEnabled()) {
logger.debug("Bean factory for " + getDisplayName() + ": " + beanFactory);
}
return beanFactory;
}
核心方法refreshBeanFactory()
protected final void refreshBeanFactory() throws BeansException {
if (hasBeanFactory()) {
destroyBeans();
closeBeanFactory();
}
try {
DefaultListableBeanFactory beanFactory = createBeanFactory();
beanFactory.setSerializationId(getId());
customizeBeanFactory(beanFactory);
loadBeanDefinitions(beanFactory);
synchronized (this.beanFactoryMonitor) {
this.beanFactory = beanFactory;
}
}
catch (IOException ex) {
throw new ApplicationContextException("I/O error parsing bean definition source for " + getDisplayName(), ex);
}
}
- createBeanFactory();
- 设置beanFactory属性
- loadBeanDefinitions(beanFactory);
loadBeanDefinitions(beanFactory)
解析bean定义,有几个bean就有几个BeanDefinition。注意,Spring并不是拿到配置就直接用反射实例化bean,而是先将bean配置解析为BeanDefinition。
BeanDefinition保存了实例化bean需要的一切信息,包括属性,依赖等。以ConcurrentHashMap<String, BeanDefinition>保存在DefaultListableBeanFactory的beanDefinitionMap里。

prepareBeanFactory(beanFactory)
设置beanFactory的其余属性
postProcessBeanFactory(beanFactory)
空实现,给子类一个机会,自定义beanFactory后置处理器
BeanFactoryPostProcessor定义:
public interface BeanFactoryPostProcessor {
void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException;
}
invokeBeanFactoryPostProcessors(beanFactory)
执行上一步中的beanFactory后置处理器的回调方法
void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory)
registerBeanPostProcessors(beanFactory)
注册bean后置处理器,实现bean初始化前后的自定义逻辑
BeanPostProcessor定义:
public interface BeanPostProcessor {
// 在bean实例化前调用
Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException;
// 在bean实例化后调用
Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException;
}
initMessageSource()
注册国际化相关bean
initApplicationEventMulticaster()
初始化Spring事件发布相关bean
onRefresh()
空实现,给子类一个机会,初始化特殊bean
registerListeners()
注册监听器
finishBeanFactoryInitialization(beanFactory)
实例化所有非懒加载的bean
直到这里,才开始真正实例化bean
protected void finishBeanFactoryInitialization(ConfigurableListableBeanFactory beanFactory) {
// 1. 实例化bean的类型转换器
if (beanFactory.containsBean(CONVERSION_SERVICE_BEAN_NAME) &&
beanFactory.isTypeMatch(CONVERSION_SERVICE_BEAN_NAME, ConversionService.class)) {
beanFactory.setConversionService(
beanFactory.getBean(CONVERSION_SERVICE_BEAN_NAME, ConversionService.class));
}
// 2. 实例化属性占位符解析器
if (!beanFactory.hasEmbeddedValueResolver()) {
beanFactory.addEmbeddedValueResolver(new StringValueResolver() {
@Override
public String resolveStringValue(String strVal) {
return getEnvironment().resolvePlaceholders(strVal);
}
});
}
// 3. 实例化LoadTimeWeaverAware
String[] weaverAwareNames = beanFactory.getBeanNamesForType(LoadTimeWeaverAware.class, false, false);
for (String weaverAwareName : weaverAwareNames) {
getBean(weaverAwareName);
}
// 4. 停止使用临时ClassLoader进行类型匹配
beanFactory.setTempClassLoader(null);
// 5. 禁止再修改bean定义
beanFactory.freezeConfiguration();
// 6. 实例化所有非懒加载单例bean
beanFactory.preInstantiateSingletons();
}
preInstantiateSingletons()
- 根据每一个bean定义,实例化bean
- 为每一个实现SmartInitializingSingleton的bean执行回调方法
实例化bean部分的代码:
for (String beanName : beanNames) {
// 获取bean定义
RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName);
// 只有不是abstract、单例且不是懒加载的bean才在这里实例化
if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) {
// 如果是FactoryBean
if (isFactoryBean(beanName)) {
// 先实例化实例对应的FactoryBean
final FactoryBean<?> factory = (FactoryBean<?>) getBean(FACTORY_BEAN_PREFIX + beanName);
boolean isEagerInit;
if (System.getSecurityManager() != null && factory instanceof SmartFactoryBean) {
isEagerInit = AccessController.doPrivileged(new PrivilegedAction<Boolean>() {
@Override
public Boolean run() {
return ((SmartFactoryBean<?>) factory).isEagerInit();
}
}, getAccessControlContext());
}
else {
isEagerInit = (factory instanceof SmartFactoryBean &&
((SmartFactoryBean<?>) factory).isEagerInit());
}
if (isEagerInit) {
// 使用FactoryBean的getObject()方法返回真正的实例
getBean(beanName);
}
}
else {
getBean(beanName);
}
}
}
getBean(String name)
该方法调用了一个doGetBean,doGetBean代码较长,而且有部分代码是为了解决并发场景下单例的生成,我们挑出重点的看:
- 从父BeanFactory检查是否存在该bean的定义,如果存在,委托父BeanFactory来实例化
BeanFactory parentBeanFactory = getParentBeanFactory();
if (parentBeanFactory != null && !containsBeanDefinition(beanName)) {
// Not found -> check parent.
String nameToLookup = originalBeanName(name);
if (args != null) {
// Delegation to parent with explicit args.
return (T) parentBeanFactory.getBean(nameToLookup, args);
}
else {
// No args -> delegate to standard getBean method.
return parentBeanFactory.getBean(nameToLookup, requiredType);
}
}
- 获得bean定义,如果存在依赖,先实例化每一个依赖bean,注意:不允许循环依赖
final RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
checkMergedBeanDefinition(mbd, beanName, args);
// Guarantee initialization of beans that the current bean depends on.
String[] dependsOn = mbd.getDependsOn();
//如果存在依赖,先实例化每一个依赖bean
if (dependsOn != null) {
// 实例化每一个依赖bean
for (String dep : dependsOn) {
// 检查循环依赖
if (isDependent(beanName, dep)) {
throw new BeanCreationException(mbd.getResourceDescription(), beanName,
"Circular depends-on relationship between '" + beanName + "' and '" + dep + "'");
}
// 实例化依赖bean
registerDependentBean(dep, beanName);
try {
getBean(dep);
}
catch (NoSuchBeanDefinitionException ex) {
throw new BeanCreationException(mbd.getResourceDescription(), beanName,
"'" + beanName + "' depends on missing bean '" + dep + "'", ex);
}
}
}
- 实例化bean
方法调用流程:
createBean > doCreateBean > populateBean
其中doCreateBean:
- 从BeanDefinition生成BeanWrapper
- 将BeanWrapper和BeanDefinition.getPropertyValues() 传给populateBean,实例化bean
finishRefresh()
protected void finishRefresh() {
// 初始化生命周期处理器
initLifecycleProcessor();
// 刷新生命周期处理器状态 running = true
getLifecycleProcessor().onRefresh();
// 发布上下文初始化完成事件ContextRefreshedEvent
publishEvent(new ContextRefreshedEvent(this));
// 如果处于活动状态,将自己注册到LiveBeans
LiveBeansView.registerApplicationContext(this);
}
总结
Spring IoC Container时序图

Spring IoC Container源码分析(二)-bean初始化流程的更多相关文章
- Spring IOC 容器源码分析 - 余下的初始化工作
1. 简介 本篇文章是"Spring IOC 容器源码分析"系列文章的最后一篇文章,本篇文章所分析的对象是 initializeBean 方法,该方法用于对已完成属性填充的 bea ...
- Spring IOC 容器源码分析 - 填充属性到 bean 原始对象
1. 简介 本篇文章,我们来一起了解一下 Spring 是如何将配置文件中的属性值填充到 bean 对象中的.我在前面几篇文章中介绍过 Spring 创建 bean 的流程,即 Spring 先通过反 ...
- Spring IOC 容器源码分析 - 创建原始 bean 对象
1. 简介 本篇文章是上一篇文章(创建单例 bean 的过程)的延续.在上一篇文章中,我们从战略层面上领略了doCreateBean方法的全过程.本篇文章,我们就从战术的层面上,详细分析doCreat ...
- Spring IOC 容器源码分析 - 创建单例 bean 的过程
1. 简介 在上一篇文章中,我比较详细的分析了获取 bean 的方法,也就是getBean(String)的实现逻辑.对于已实例化好的单例 bean,getBean(String) 方法并不会再一次去 ...
- Spring IOC 容器源码分析 - 获取单例 bean
1. 简介 为了写 Spring IOC 容器源码分析系列的文章,我特地写了一篇 Spring IOC 容器的导读文章.在导读一文中,我介绍了 Spring 的一些特性以及阅读 Spring 源码的一 ...
- Spring IOC 容器源码分析系列文章导读
1. 简介 Spring 是一个轻量级的企业级应用开发框架,于 2004 年由 Rod Johnson 发布了 1.0 版本.经过十几年的迭代,现在的 Spring 框架已经非常成熟了.Spring ...
- Spring IOC 容器源码分析 - 循环依赖的解决办法
1. 简介 本文,我们来看一下 Spring 是如何解决循环依赖问题的.在本篇文章中,我会首先向大家介绍一下什么是循环依赖.然后,进入源码分析阶段.为了更好的说明 Spring 解决循环依赖的办法,我 ...
- 十、Spring之BeanFactory源码分析(二)
Spring之BeanFactory源码分析(二) 前言 在前面我们简单的分析了BeanFactory的结构,ListableBeanFactory,HierarchicalBeanFactory,A ...
- 最简 Spring IOC 容器源码分析
前言 BeanDefinition BeanFactory 简介 Web 容器启动过程 bean 的加载 FactoryBean 循环依赖 bean 生命周期 公众号 前言 许多文章都是分析的 xml ...
随机推荐
- 三、Mongodb Java中的使用
添加maven依赖 <!--mongodb 驱动--> <dependency> <groupId>org.mongodb</groupId> < ...
- LeetCode29 Medium 不用除号实现快速除法
本文始发于个人公众号:TechFlow,原创不易,求个关注 链接 Divide Two Integers 难度 Medium 描述 给定两个整数,被除数和除数,要求在不使用除号的情况下计算出两数的商 ...
- Digital Twin 数字孪生
GE的一个NB视频:http://v.youku.com/v_show/id_XMjk0NTMzODIyNA==.html http://www.gongkong.com/news/201701/35 ...
- kubernetes集合
kubernetes集合 kubernetes(1):kubernetes简介和组件 kubernetes(2):yum安装kubernetes kubernetes(3):kubeadm安装k8s1 ...
- Memcache 安装配置使用
Memcached 是一个高性能的分布式内存对象缓存系统,用于动态Web应用以减轻数据库负载. ...
- apache 负载均衡
此次使用mod_proxy的方式来实现的,因为在Apache2以上的版本中已经集成了,因此不需要再另行安装和配置了. 只需要把注释去掉即可,去掉以下模块的注释: LoadModule proxy_mo ...
- Charm Bracelet 一维01背包
A - Charm Bracelet Time Limit:1000MS Memory Limit:65536KB 64bit IO Format:%lld & %llu Su ...
- 大数相乘----C语言
/* 大数相乘: 因为是大数,乘积肯定超出了能定义的范围,因此考虑用数组存储,定义三个数组,分别存储乘数,被乘数和积. 规则与平常手算一样,从个位开始分别与被乘数的每一位相乘,但是有一点不同的是:我们 ...
- flex布局小结
2009年,W3C 提出了一种新的方案----Flex 布局,可以简便.完整.响应式地实现各种页面布局.目前,它已经得到了所有浏览器的支持. Flex 是 Flexible Box 的缩写,意为&qu ...
- Linux kernel简介
内核体系设计分:单内核,微内核 windows是微内核设计. Linux是单内核设计,但充分借鉴了为微内核体系的优点,为内核引入了模块化机制. 内核的组成部分 kernel:内核核心,一般为bz压缩的 ...