Spring Bean的生命周期往深入去看,不是簡單的幾句話能講完,早就想寫相關(guān)的內(nèi)容,但一直覺得工作量不會低,就沒有動筆寫。拆成幾篇來寫,這樣也不好給自己太大的壓力。

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>
文件結(jié)構(gòu)就是這個簡單,如下

image.png
過程分析
- 新建ClassPathXmlApplicationContext實(shí)例的時候,最終實(shí)例化的構(gòu)造方法如下
- configLocations配置文件位置,支持字符串?dāng)?shù)組
- refresh是否自動的刷新上下文,否則在配置之后要手動的調(diào)用refresh方法
- parent 父級的上下文
public ClassPathXmlApplicationContext(String[] configLocations, boolean refresh, ApplicationContext parent)
throws BeansException {
super(parent);
setConfigLocations(configLocations);
if (refresh) {
refresh();
}
}
其最終的實(shí)例化的父類為:
//創(chuàng)建AbstractApplicationContext
public AbstractApplicationContext() {
this.resourcePatternResolver = getResourcePatternResolver();
}
public AbstractApplicationContext(ApplicationContext parent) {
this();
setParent(parent);
}
protected ResourcePatternResolver getResourcePatternResolver() {
return new PathMatchingResourcePatternResolver(this);
}
- 設(shè)置配置文件的位置,
setConfigLocation(String location)
//支持可變參數(shù),如果locations不存在,那么默認(rèn)為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, 調(diào)用refresh()方法,這里先貼出來整個方法, Refreash方法是容器中非常重要的一個方法,一時間這里不好完全講說明白,先把每個方法的用途注釋寫上,接下來我們再一起看看其內(nèi)部是怎么回事
public void refresh() throws BeansException, IllegalStateException {
synchronized (this.startupShutdownMonitor) {
// 準(zhǔn)備刷新的Context.
prepareRefresh();
// Tell the subclass to refresh the internal bean factory.
// 告訴子類刷新內(nèi)部的Bean Factory
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
// Prepare the bean factory for use in this context.
// 準(zhǔn)備好Context使用的Bean Factory
prepareBeanFactory(beanFactory);
try {
// Allows post-processing of the bean factory in context subclasses.
// 設(shè)置Bean的 postPorcess
postProcessBeanFactory(beanFactory);
// Invoke factory processors registered as beans in the context.
// 調(diào)用BeanFactory的 postProcess
invokeBeanFactoryPostProcessors(beanFactory);
// Register bean processors that intercept bean creation.
// 注冊Bean的PostProcess
registerBeanPostProcessors(beanFactory);
// Initialize message source for this context.
//對上下文中的消息源進(jìn)行初始化
initMessageSource();
// Initialize event multicaster for this context.
//初始化上下文的事件機(jī)制
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.
//實(shí)例化所有的非懶加載的 Singleton
finishBeanFactoryInitialization(beanFactory);
// Last step: publish corresponding event.
// 發(fā)布相關(guān)的事件
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避免對資源產(chǎn)生不好的影響
destroyBeans();
// Reset 'active' flag.
//重置 active 標(biāo)志
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)
最后
讀代碼,如果條理清晰,是一件比較爽的工作,盡量不要急功近利,我們一步一步來,壓力都會比較小一點(diǎn)。