Spring IOC容器启动流程分析(一)
1、准备工作
0 引言
1 引入jar包
项目通过maven方式构建,引入jar包:
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.3.10</version>
</dependency>
目前5.3.10为Spring Framework的最新稳定版本。通过引入spring-context,maven为自动帮我们引入其它相关jar包:spring-core、spring-beans、spring-expression、spring-aop
2 创建bean
public class TestBean {
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
3 创建配置文件
<?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
http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="testBean" class="test.spring.ioc.TestBean" />
</beans>
4 执行main方法
public class Main {
public static void main(String[] args) {
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("spring-benas.xml");
TestBean testBean = context.getBean("testBean", TestBean.class);
}
}
在main方法中加入断点,进行debug,开始分析容器启动流程
2 启动流程主要步骤
1、调用父类构造函数,进行部分对象的初始化
public ClassPathXmlApplicationContext(
String[] configLocations, boolean refresh, @Nullable ApplicationContext parent)
throws BeansException {
super(parent);
setConfigLocations(configLocations);
if (refresh) {
refresh();
}
}
super(parent) 最终会调用到AbstractApplicationContext的构造方法,创建一个新的应用上下文
/**
* Create a new AbstractApplicationContext with the given parent context.
* @param parent the parent context
*/
public AbstractApplicationContext(@Nullable ApplicationContext parent) {
this();
setParent(parent);
}
由于入参parent为空,所以实际只需要关注this()方法就可以了,即当前类的无参构造函数
/**
* Create a new AbstractApplicationContext with no parent.
*/
public AbstractApplicationContext() {
this.resourcePatternResolver = getResourcePatternResolver();
}
获取ResourcePatternResolver
2、setConfigLocations 将配置文件设置到变量configLocations中
/**
* Set the config locations for this application context.
* <p>If not set, the implementation may use a default as appropriate.
*/
public void setConfigLocations(@Nullable 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;
}
}
其中locations即我们传入的配置文件
3、调用refresh()方法,创建实例
refresh()方法是Spring启动最重要的方法
@Override
public void refresh() throws BeansException, IllegalStateException {
synchronized (this.startupShutdownMonitor) {
StartupStep contextRefresh = this.applicationStartup.start("spring.context.refresh");
// 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);
try {
// Allows post-processing of the bean factory in context subclasses.
postProcessBeanFactory(beanFactory);
StartupStep beanPostProcess = this.applicationStartup.start("spring.context.beans.post-process");
// Invoke factory processors registered as beans in the context.
invokeBeanFactoryPostProcessors(beanFactory);
// Register bean processors that intercept bean creation.
registerBeanPostProcessors(beanFactory);
beanPostProcess.end();
// 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();
}
catch (BeansException ex) {
if (logger.isWarnEnabled()) {
logger.warn("Exception encountered during context initialization - " +
"cancelling refresh attempt: " + ex);
}
// Destroy already created singletons to avoid dangling resources.
destroyBeans();
// Reset 'active' flag.
cancelRefresh(ex);
// Propagate exception to caller.
throw ex;
}
finally {
// Reset common introspection caches in Spring's core, since we
// might not ever need metadata for singleton beans anymore...
resetCommonCaches();
contextRefresh.end();
}
}
}
startupShutdownMonitor作为锁对象,在refresh和destroy时使用,其创建过程在super()中完成
/** Synchronization monitor for the "refresh" and "destroy". */
private final Object startupShutdownMonitor = new Object();
1、prepareRefresh
2、obtainFreshBeanFactory()
3、prepareBeanFactory(beanFactory);
4、postProcessBeanFactory(beanFactory);
5、this.applicationStartup.start("spring.context.beans.post-process");
6、invokeBeanFactoryPostProcessors(beanFactory);
7、registerBeanPostProcessors(beanFactory);
8、beanPostProcess.end();
9、initMessageSource(); 完成国际化操作
10、initApplicationEventMulticaster();
11、onRefresh();
12、registerListeners(); 注册监听器
13、finishBeanFactoryInitialization(beanFactory);
14、finishRefresh();