1、Spring源码环境搭建参照
2、 IoC容器体系
IoC是Spring的核心模块,抽象了对象管理、依赖关系管理的框架解决方案。Spring提供了很多的容器,其中BeanFactory是顶层容器(根容器),不能被实例化,它定义了所有IoC容器必须遵从的一套原则,具体的容器实现可以增加额外的功能,比如经常用到的ApplicationContext,其下更具体的实现如ClassPathXmlApplicationContext包含了解析XML的等内容,AnnotationConfigApplicationContextze则是包含了注解解析等一系列的内容。这也表示SpringIoC容器继承体系非常灵活,需要使用哪个层次就使用哪个层次即可,不需要一股脑的全部使用。
BeanFactory顶级接口方法栈如下 :
BeanFactory的容器继承体系:
通过BeanFactory的接口继承体系,可以看到经常使用的ApplicationContext除了继承了BeanFactory的子接口,还继承了MessageSource、ResourceLoader等接口,因此ApplicationContext提供的功能也就更加丰富全面了
本文就以ClassPathXmlApplicationContext,来探究Spring IoC容器的初始化流程。
3、具体源码探究
Bean生命周期的关键时机点
通过创建几个Bean类,让其分别实现 BeanPostProcessor(Bean的后置处理器)、BeanFactoryPostProcessor(BeanFactory的后置处理器),通过断点观察调用栈来分析Bean对象创建和管理关键点的出发时机
UserBean类
public class UserBean implements InitializingBean{
/**
* 构造函数
*/
public UserBean(){
System.out.println("UserBean 构造器...");
}
/**
* InitializingBean 接口实现
*/
public void afterPropertiesSet() throws Exception {
System.out.println("UserBean afterPropertiesSet...");
}
}
public class MyBeanPostProcessor implements BeanPostProcessor {
public MyBeanPostProcessor() {
System.out.println("BeanPostProcessor 实现类构造函数...");
}
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
if("userBean".equals(beanName)) {
System.out.println("BeanPostProcessor 实现类 postProcessBeforeInitialization 方法被调用中......");
}
return bean;
}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
if("userBean".equals(beanName)) {
System.out.println("BeanPostProcessor 实现类 postProcessAfterInitialization 方法被调用中......");
}
return bean;
}
}
public class MyBeanFactoryPostProcessor implements BeanFactoryPostProcessor {
public MyBeanFactoryPostProcessor() {
System.out.println("BeanFactoryPostProcessor的实现类构造函数...");
}
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
System.out.println("BeanFactoryPostProcessor的实现方法调用中......");
}
}
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd
">
<bean id="userBean" class="com.demo.spring.UserBean"/>
<bean id="myBeanFactoryPostProcessor" class="com.demo.spring.MyBeanFactoryPostProcessor"/>
<bean id="myBeanPostProcessor" class="com.demo.spring.MyBeanPostProcessor"/>
</beans>
ClassPathXmlApplicationContext容器分析代码:
@Test
public void testIoC() {
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("classpath:applicationContext.xml");
UserBean userBean= applicationContext.getBean(UserBean.class);
System.out.println(userBean);
}
(1)分析Bean的创建是在容器初始化的时候还是在getBean时
通过断点调试,可以发现在没有设置延迟加载的情况下,Bean的创建是在容器初始化的时候完成的
(2)分析构造函数调用情况
通过观察调用栈,可以发现构造函数的调用时机是在AbstractApplicationContext类refresh⽅法的 fifinishBeanFactoryInitialization(beanFactory)处;
(3)分析 InitializingBean 的afterPropertiesSet初始化方法调用情况
观察调用栈
通过观察,可以发现InitializingBean中afterPropertiesSet方法的调用时机也是在AbstractApplicationContext类refresh⽅法的 fifinishBeanFactoryInitialization(beanFactory)处;
(4)分析BeanFactoryPostProcessor 初始化和调⽤情况
分别在MyBeanFactoryPostProcessor的构造函数跟postProcessbeanFactory方法处打断点,观察调用栈,发现
BeanFactoryPostProcessor初始化在AbstractApplicationContext类refresh⽅法的invokeBeanFactoryPostProcessors(beanFactory);
postProcessBeanFactory 调⽤在AbstractApplicationContext类refresh⽅法的 invokeBeanFactoryPostProcessors(beanFactory);
(5)分析BeanPostProcessor初始化和调用情况
分别在MyBeanPostProcessor的构造函数、postProcessorBeforeInitialization和postProcessorAfterInitialization方法处打断点,观察调用栈,发现
BeanPostProcessor 初始化在AbstractApplicationContext类refresh⽅法的 registerBeanPostProcessors(beanFactory);
postProcessBeforeInitialization 调⽤在AbstractApplicationContext类refresh⽅法的 finishBeanFactoryInitialization(beanFactory);
postProcessAfterInitialization 调⽤在AbstractApplicationContext类refresh⽅法的 finishBeanFactoryInitialization(beanFactory);
(6)总结
根据上⾯的调试分析,我们发现 Bean对象创建的⼏个关键时机点代码层级的调⽤都在 AbstractApplicationContext 类 的 refresh ⽅法中,可⻅这个⽅法对于Spring IoC 容器初始化来说相当 关键,汇总如下:
关键点 | 触发代码 |
构造器 | refresh#fifinishBeanFactoryInitialization(beanFactory)(beanFactory) |
BeanFactoryPostProcessor 初始化 | refresh#invokeBeanFactoryPostProcessors(beanFactory) |
BeanFactoryPostProcessor ⽅法调⽤ | refresh#invokeBeanFactoryPostProcessors(beanFactory) |
BeanPostProcessor 初始化 | registerBeanPostProcessors(beanFactory) |
BeanPostProcessor ⽅法调⽤ | refresh#fifinishBeanFactoryInitialization(beanFactory) |
4、SpringIoC主流程
由上分析可知,Spring IoC 容器初始化的关键环节就在 AbstractApplicationContext#refresh() ⽅法中 ,我们查看 refresh ⽅法来俯瞰容器创建的主体流程,主体流程下的具体⼦流程我们后⾯再来讨论。
进入ClassPathXmlApplicationContext的构造方法
下图中的refresh()方法就是IOC容器初始化的关键方法了
点击构造方法中的refresh()方法进入 AbstractApplicationContext的refresh()方法
@Override
public void refresh() throws BeansException, IllegalStateException {
synchronized (this.startupShutdownMonitor) {
// 第一步:刷新前的预处理
prepareRefresh();
/*
* 第二步:
* 获取beanFactory 默认实现是DefaultListableBeanFactory
* 加载BeanDefition 并注册到BeanDefitionRegistry
*/
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
//第三步:BeanFactory的预准备⼯作(BeanFactory进⾏⼀些设置,⽐如context的类加载器等)
prepareBeanFactory(beanFactory);
try {
// 第四步:BeanFactory准备⼯作完成后进⾏的后置处理⼯作
postProcessBeanFactory(beanFactory);
// 第五步:实例化并调⽤实现了BeanFactoryPostProcessor接⼝的Bean
invokeBeanFactoryPostProcessors(beanFactory);
// 第六步:注册BeanPostProcessor(Bean的后置处理器),在创建bean的前后等执⾏
registerBeanPostProcessors(beanFactory);
// 第七步:初始化MessageSource组件(做国际化功能;消息绑定,消息解析);
initMessageSource();
// 第⼋步:初始化事件派发器
initApplicationEventMulticaster();
// 第九步:⼦类重写这个⽅法,在容器刷新的时候可以⾃定义逻辑
onRefresh();
// 第⼗步:注册应⽤的监听器。就是注册实现了ApplicationListener接⼝的监听器bean
registerListeners();
/*
第⼗⼀步:
初始化所有剩下的⾮懒加载的单例bean
初始化创建⾮懒加载⽅式的单例Bean实例(未设置属性)
填充属性
初始化⽅法调⽤(⽐如调⽤afterPropertiesSet⽅法、init-method⽅法)
调⽤BeanPostProcessor(后置处理器)对实例bean进⾏后置处
*/
finishBeanFactoryInitialization(beanFactory);
/*
第⼗⼆步:完成context的刷新。主要是调⽤LifecycleProcessor的onRefresh()⽅
法,并且发布事件 (ContextRefreshedEvent)
*/
finishRefresh();
}
catch (BeansException ex) {
if (logger.isWarnEnabled()) {
logger.warn("Exception encountered during context initialization - " +
"cancelling refresh attempt: " + ex);
}
// 销毁已创建的单例bean
destroyBeans();
// 重置容器标志
cancelRefresh(ex);
// Propagate exception to caller.
throw ex;
}
finally {
// 重置公共内省缓存
resetCommonCaches();
}
}
}
以上代码就是整个SpringIOC容器初始化的主流程