一、
概述
二、
Spring
初始化之旅
a)
Spring
初始化的时候首先要运行的类为:
org.springframework.web.context. ContextLoaderListener
或
org.springframework.web.context. ContextLoaderServlet
。
它们在初始化函数里无一例外地实例化了
ContextLoader
类
,
然后调用了它的函数
public WebApplicationContext initWebApplicationContext(ServletContext )
。
接下来看一下在这个方法里干了写什么
b)
在他的方法体内,关键是“
this.context = createWebApplicationContext(servletContext, parent);
”新建了一个“
ConfigurableWebApplicationContext
”类型的对象,在这一步实例化中几乎完成了所有的
spring
初始化工作。读取了所有的
spring
配置文件。它的工作步骤如下所述。
c)
首先,在将“
ConfigurableWebApplicationContext
”类型的对象实例化以后(这个对象实际的类型是这个包内的
XmlWebApplicationContext
),然后又给这个实例设置了三个属性,“
wac.setParent(parent);
”在默认的初始化过程中这一步设置了一个
null
值,然后又设置了一个“
wac.setServletContext(servletContext);
”,将系统默认的上下文设置进来,比较重要的是下面这一段:
if (configLocation != null) {
//
读取
spring
的应用配置文件
wac.setConfigLocations(StringUtils.tokenizeToStringArray(configLocation,Configurabl eWebApplicationContext.CONFIG_LOCATION_DELIMITERS));
}
它将我们的配置文件名放置到
wac
变量中,以待在后续的操作中使用。然后调用
“
wac.refresh();
”完成主要的初始化
BeanFactory
的操作。如下。
d)
首先我们应该看一下我们实例化的对象
org.springframework.web.context.support.XmlWebApplicationContext
的类图:
e)
“
wac.refresh();
”从类结构里我们能找到这个方法来自它的父类:
AbstractApplicationContext
在它的
refresh()
方法内我们可以看到
spring
的复杂逻辑。
首先执行了
refreshBeanFactory();
(来自
AbstractRefreshableApplicationContext
)见
f),
f)
refreshBeanFactory();
这个方法由负责维护变量
beanFactory
的子类
AbstractRefreshableApplicationContext
实现,默认情况下这个方法直接实例化一个新的
DefaultListableBeanFactory
类型的
BeanFacorty,
然后调用一个起缓冲作用的配置函数生成一个将
beanFacroty
包装起来的对象
beanDefinitionReader
,然后对这个对象进行属性配置,实际上该方法主要负责生成一个临时的操作对象,对应调用的函数为“
loadBeanDefinitions(beanFactory);
”该方法为初始化期间较为重要的一个。
该方法来自其子类:
AbstractRefreshableWebApplicationContext
对应的函数:
protected void loadBeanDefinitions(DefaultListableBeanFactory)
,然后这里又调用了自己定义的
protected void loadBeanDefinitions(XmlBeanDefinitionReader)
方法。此时,它就使用到了在
c)
中设置了的(
wac.setConfigLocations(……))
我们开发中密切相关的配置文件。(同时也要记住此时这个函数的参数
beanDefinitionReader
,之前已经设置了“
beanDefinitionReader.setResourceLoader(this);
”这里的
this
是我们在前面见到的
XmlWebApplicationContext
(一个定义好了的上下文))。接着往下:
“
reader.loadBeanDefinitions(configLocations[i]);
”
reader
开始加载我们配置文件内的东西了,不过真正复杂的实现此时才开始,我们继续往下走,在接下来的方法内默认情况下会执行:
if (resourceLoader instanceof ResourcePatternResolver)
(该判断条件为
true
)
,
由于从上面我们知道:
beanDefinitionReader.setResourceLoader(this);
而
this
的类型为:
XmlWebApplicationContext
所以
((ResourcePatternResolver) resourceLoader).getResources(location);
得到一个
Resource[]
数组,接下来调用:
int loadCount = loadBeanDefinitions(resources);
该函数继续调用自己子类定义的一系列临时接口最终执行到
return doLoadBeanDefinitions(inputSource, encodedResource.getResource());
在这个函数内初始化了处理
xml
文件的一些对象并将用户的配置文件解析为一个
Document
对象。然后又执行了一系列函数直到
return parser.registerBeanDefinitions(this, doc, resource);
这个函数来自我们新建的
DefaultXmlBeanDefinitionParser
,在这个类里最终执行了对
xml
文件的解析工作和对
beanFacroty
变量执行了设置工作。
g)
终于我们从这些繁杂的逻辑中跳了出来,继续执行
AbstractApplicationContext.refresh()
下面的工作,后续的代码主要仍旧是往一些常量里面设值。
此时
spring
初始化过程就结束了。