Spring源码学习
 

一、             概述 <o:p></o:p>

二、             Spring 初始化之旅 <o:p></o:p>

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 的类图:

 

<o:p> </o:p>

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 初始化过程就结束了


评述:启动过程如下:
1.创建一个ApplicationContext的实例ac
2.读取配置文件,ac简单的设置(比如有多少bean)
3.所有的beanfactory后处理开始以此执行
4.开始创建bean的实例
5.进行注入(如果有其他bean,迭代执行)
6.如何实现一些接口(BeanFactoryAware, BeanNameAware)以此该bean执行相应方法
7.所有的bean后处理开始执行,中间如果实现InitializingBean,该bean执行相应方法)