准备

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>();
}
  1. 设置上下文基本信息,如startupDate(启动时刻)、closed(是否关闭)、active(是否存活)等等。
  2. 解析占位符资源,并验证标记为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);
}
}
  1. createBeanFactory();
  2. 设置beanFactory属性
  3. 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()

  1. 根据每一个bean定义,实例化bean
  2. 为每一个实现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代码较长,而且有部分代码是为了解决并发场景下单例的生成,我们挑出重点的看:

  1. 从父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);
}
}
  1. 获得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);
}
}
}
  1. 实例化bean

方法调用流程:

createBean > doCreateBean > populateBean

其中doCreateBean:

  1. 从BeanDefinition生成BeanWrapper
  2. 将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初始化流程的更多相关文章

  1. Spring IOC 容器源码分析 - 余下的初始化工作

    1. 简介 本篇文章是"Spring IOC 容器源码分析"系列文章的最后一篇文章,本篇文章所分析的对象是 initializeBean 方法,该方法用于对已完成属性填充的 bea ...

  2. Spring IOC 容器源码分析 - 填充属性到 bean 原始对象

    1. 简介 本篇文章,我们来一起了解一下 Spring 是如何将配置文件中的属性值填充到 bean 对象中的.我在前面几篇文章中介绍过 Spring 创建 bean 的流程,即 Spring 先通过反 ...

  3. Spring IOC 容器源码分析 - 创建原始 bean 对象

    1. 简介 本篇文章是上一篇文章(创建单例 bean 的过程)的延续.在上一篇文章中,我们从战略层面上领略了doCreateBean方法的全过程.本篇文章,我们就从战术的层面上,详细分析doCreat ...

  4. Spring IOC 容器源码分析 - 创建单例 bean 的过程

    1. 简介 在上一篇文章中,我比较详细的分析了获取 bean 的方法,也就是getBean(String)的实现逻辑.对于已实例化好的单例 bean,getBean(String) 方法并不会再一次去 ...

  5. Spring IOC 容器源码分析 - 获取单例 bean

    1. 简介 为了写 Spring IOC 容器源码分析系列的文章,我特地写了一篇 Spring IOC 容器的导读文章.在导读一文中,我介绍了 Spring 的一些特性以及阅读 Spring 源码的一 ...

  6. Spring IOC 容器源码分析系列文章导读

    1. 简介 Spring 是一个轻量级的企业级应用开发框架,于 2004 年由 Rod Johnson 发布了 1.0 版本.经过十几年的迭代,现在的 Spring 框架已经非常成熟了.Spring ...

  7. Spring IOC 容器源码分析 - 循环依赖的解决办法

    1. 简介 本文,我们来看一下 Spring 是如何解决循环依赖问题的.在本篇文章中,我会首先向大家介绍一下什么是循环依赖.然后,进入源码分析阶段.为了更好的说明 Spring 解决循环依赖的办法,我 ...

  8. 十、Spring之BeanFactory源码分析(二)

    Spring之BeanFactory源码分析(二) 前言 在前面我们简单的分析了BeanFactory的结构,ListableBeanFactory,HierarchicalBeanFactory,A ...

  9. 最简 Spring IOC 容器源码分析

    前言 BeanDefinition BeanFactory 简介 Web 容器启动过程 bean 的加载 FactoryBean 循环依赖 bean 生命周期 公众号 前言 许多文章都是分析的 xml ...

随机推荐

  1. 脚本、脚本语言、shell脚本

    脚本是批处理文件的延伸,是一种纯文本保存的程序,一般来说的计算机脚本程序是确定的一系列控制计算机进行运算操作动作的组合,在其中可以实现一定的逻辑分支等.脚本程序相对一般程序开发来说比较接近自然语言,可 ...

  2. 题解【Luogu6022 快乐水】

    \[ Preface \] 大概在半年前出过这道((( 然后当天读完这题,把自己写的 std 改了一下 ll 和特判信息交上去就 A 了. 捡了个大便宜. \[ Description \] 你一开始 ...

  3. Python实现IOC控制反转

    思路: 用一个字典存储beanName和资源 初始化时先将beanName和资源注册到字典中 然后用一个Dscriptor类根据beanName动态请求资源,从而实现控制反转 # -*- coding ...

  4. 吴恩达deepLearning.ai循环神经网络RNN学习笔记_看图就懂了!!!(理论篇)

    前言 目录: RNN提出的背景 - 一个问题 - 为什么不用标准神经网络 - RNN模型怎么解决这个问题 - RNN模型适用的数据特征 - RNN几种类型 RNN模型结构 - RNN block - ...

  5. Effective Java, Third Edition

    https://github.com/jbloch/effective-java-3e-source-code 网址是 Effetive java的源码 effective-java-3e-sourc ...

  6. jenkin docker node 自动化部署配置

    jenkins 安装必须插件 NodeJS Plugin Publish Over SSH 1:新建一个任务,选择构建一个自由风格的软件项目 2:源码管理选择Git 2.1 填写Git项目地址Repo ...

  7. JAVA系统架构高并发解决方案 分布式缓存 分布式事务解决方案

    JAVA系统架构高并发解决方案 分布式缓存 分布式事务解决方案

  8. 邓士鹏【MySql大全】

    禁止使用系统关键字: typename 1.计算两个日期的时间差函数 SELECT TIMESTAMPDIFF(MONTH,'2009-10-01','2009-09-01'); interval可是 ...

  9. Nginx-4.Nginx如何处理请求

    原文 基于server_name 的虚拟站点 Nginx首先需要确定使用哪个server来处理请求.举个简单的例子,有下面几个server 第一个,监听80端口,为org站点 server { lis ...

  10. springCloud进阶(微服务架构&Eureka)

    springCloud进阶(微服务架构&Eureka) 1. 微服务集群 1.1 为什么要集群 为了提供并发量,有时同一个服务提供者可以部署多个(商品服务).这个客户端在调用时要根据一定的负责 ...