一、 概述
二、 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 初始化过程就结束了。