Spring Bean的生命周期往深入去看,不是簡單的幾句話能講完阳懂,早就想寫相關的內容,但一直覺得工作量不會低柜思,就沒有動筆寫岩调。拆成幾篇來寫,這樣也不好給自己太大的壓力赡盘。
image.png
主要分析号枕,Spring容器的初始化過程,然后如何獲取Bean陨享,到最終銷毀Bean整個過程經(jīng)歷了什么東西葱淳。
代碼
主要為了分析,更多的是深入源代碼中抛姑,代碼寫的就簡單一些
//SpringApp.java文件
public class SpringApp {
public static void main(String[] args) {
ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("app.xml");
HelloWorld hello = (HelloWorld) applicationContext.getBean("hello");
hello.sayHello();
applicationContext.close();
}
}
//HelloWorld 文件
public class HelloWorld {
public void sayHello(){
System.out.println("hello World");
}
}
//app.xml文件
<?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="hello" class="me.aihe.HelloWorld">
</bean>
</beans>
文件結構就是這個簡單赞厕,如下
image.png
過程分析
- 新建ClassPathXmlApplicationContext實例的時候,最終實例化的構造方法如下
- configLocations配置文件位置定硝,支持字符串數(shù)組
- refresh是否自動的刷新上下文皿桑,否則在配置之后要手動的調用refresh方法
- parent 父級的上下文
public ClassPathXmlApplicationContext(String[] configLocations, boolean refresh, ApplicationContext parent)
throws BeansException {
super(parent);
setConfigLocations(configLocations);
if (refresh) {
refresh();
}
}
其最終的實例化的父類為:
//創(chuàng)建AbstractApplicationContext
public AbstractApplicationContext() {
this.resourcePatternResolver = getResourcePatternResolver();
}
public AbstractApplicationContext(ApplicationContext parent) {
this();
setParent(parent);
}
protected ResourcePatternResolver getResourcePatternResolver() {
return new PathMatchingResourcePatternResolver(this);
}
- 設置配置文件的位置,
setConfigLocation(String location)
//支持可變參數(shù),如果locations不存在蔬啡,那么默認為null
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;
}
}
- 刷新Context, 調用refresh()方法星爪,這里先貼出來整個方法浆西, Refreash方法是容器中非常重要的一個方法,一時間這里不好完全講說明白顽腾,先把每個方法的用途注釋寫上近零,接下來我們再一起看看其內部是怎么回事
public void refresh() throws BeansException, IllegalStateException {
synchronized (this.startupShutdownMonitor) {
// 準備刷新的Context.
prepareRefresh();
// Tell the subclass to refresh the internal bean factory.
// 告訴子類刷新內部的Bean Factory
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
// Prepare the bean factory for use in this context.
// 準備好Context使用的Bean Factory
prepareBeanFactory(beanFactory);
try {
// Allows post-processing of the bean factory in context subclasses.
// 設置Bean的 postPorcess
postProcessBeanFactory(beanFactory);
// Invoke factory processors registered as beans in the context.
// 調用BeanFactory的 postProcess
invokeBeanFactoryPostProcessors(beanFactory);
// Register bean processors that intercept bean creation.
// 注冊Bean的PostProcess
registerBeanPostProcessors(beanFactory);
// Initialize message source for this context.
//對上下文中的消息源進行初始化
initMessageSource();
// Initialize event multicaster for this context.
//初始化上下文的事件機制
initApplicationEventMulticaster();
// Initialize other special beans in specific context subclasses.
//初始化其它特殊的beans
onRefresh();
// Check for listener beans and register them.
//檢查這些Bean诺核,并且向容器注冊
registerListeners();
// Instantiate all remaining (non-lazy-init) singletons.
//實例化所有的非懶加載的 Singleton
finishBeanFactoryInitialization(beanFactory);
// Last step: publish corresponding event.
// 發(fā)布相關的事件
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.
// 銷毀已經(jīng)創(chuàng)建的singletons避免對資源產生不好的影響
destroyBeans();
// Reset 'active' flag.
//重置 active 標志
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...
//重置所有的caches
resetCommonCaches();
}
}
}
涉及到類
- PathMatchingResourcePatternResolver
- StandardEnvironment
TODO
- AbstractRefreshableConfigApplicationContext.resolvePath,其中涉及到了Environment.resolveRequiredPlaceholders(String path)
最后
讀代碼久信,如果條理清晰窖杀,是一件比較爽的工作,盡量不要急功近利裙士,我們一步一步來入客,壓力都會比較小一點。