准备

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. 2018icpc南京网络赛-E AC Challenge(状压+dfs)

    题意: n道题,每道题有ai和bi,完成这道题需要先完成若干道题,完成这道题可以得到分数t*ai+bi,其中t是时间 1s, n<=20 思路: 由n的范围状压,状态最多1e6 然后dfs,注意 ...

  2. spring中获取bean的方式

    获取bean的方式 1.可以通过上下文的getBean方法 2.可以通过@Autowired注入 定义controller @RestController @RequestMapping(" ...

  3. angularJS 传参的四种方法 【修改】

    1. 基于ui-router的页面跳转传参(1) 在AngularJS的app.js中用ui-router定义路由,比如现在有两个页面,一个页面(producers.html)放置了多个produce ...

  4. 初学maven的一些配置

    初学Maven的一些配置 1.maven的安装 2.从官网下载3.6.1版本后,高级版本可能会出现不兼容 jdk1.8 3.配置maven 在 settings.xml <settings> ...

  5. centos输入正确密码后依旧无法登陆问题

    输入正确用户名和密码时依旧无法登录. 进入单用户模式重置密码: 开机启动时,按‘E’键(倒计时结束前)进入界面 选择第二项,按‘E’键再次进入 在最后一行添加‘ 1’(空格 1) 回车键保存,回到该界 ...

  6. 字符串(Java.lang.String类)的使用

    java字符串就是Unicode字符序列,例如"Java"就是四个Unicode字符 java没有内置的字符串类型,而是在标准Java类库中提供了一个预定义的类String.每个用 ...

  7. 2019年终总结之SAP项目实践篇

    2019年终总结之SAP项目实践篇 到了临近年底,又是年终总结的时候了. 早在去年12月下旬,笔者就有展望2019年度SAP项目实践计划.当时笔者对于在2019年度SAP项目工作有三大期望或者说三大目 ...

  8. iOS闪退日志的收集和解析

    在开发过程中往往会遇见有个别用户或者测试人员反馈app的闪退现象,而项目一般集成的统计闪退的第三方库是笼统的统计了所有的闪退信息,无法去定位某一个用户提出的某一个时间点的某一个闪退问题,于是乎这个时候 ...

  9. Binder基本使用

    Android开发中,Binder是一种跨进程通信方式,而使用AIDL可以实现Binder的工作. 如何使用它是了解它的第一步,本文章主要记录使用Binder的一些步骤.(代码思路参考<Andr ...

  10. hadoop3自学入门笔记(3)-java 操作hdfs

    1.core-site.xml <configuration> <property> <name>fs.defaultFS</name> <val ...