Spring Bean的生命周期往深入去看,不是简单的几句话能讲完,早就想写相关的内容,但一直觉得工作量不会低,就没有动笔写。拆成几篇来写,这样也不好给自己太大的压力。
主要分析,Spring容器的初始化过程,然后如何获取Bean,到最终销毁Bean整个过程经历了什么东西。
代码
主要为了分析,更多的是深入源代码中,代码写的就简单一些
//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>
文件结构就是这个简单,如下
过程分析
- 新建ClassPathXmlApplicationContext实例的时候,最终实例化的构造方法如下
- configLocations配置文件位置,支持字符串数组
- refresh是否自动的刷新上下文,否则在配置之后要手动的调用refresh方法
- parent 父级的上下文
public ClassPathXmlApplicationContext(String[] configLocations, boolean refresh, ApplicationContext parent)
throws BeansException {
super(parent);
setConfigLocations(configLocations);
if (refresh) {
refresh();
}
}
其最终的实例化的父类为:
//创建AbstractApplicationContext
public AbstractApplicationContext() {
this.resourcePatternResolver = getResourcePatternResolver();
}
public AbstractApplicationContext(ApplicationContext parent) {
this();
setParent(parent);
}
protected ResourcePatternResolver getResourcePatternResolver() {
return new PathMatchingResourcePatternResolver(this);
}
- 设置配置文件的位置,
setConfigLocation(String location)
//支持可变参数,如果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.
// 发布相关的事件
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.
// 销毁已经创建的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)
最后
读代码,如果条理清晰,是一件比较爽的工作,尽量不要急功近利,我们一步一步来,压力都会比较小一点。