spring源码学习笔记-初始化(一)-概览

 

spring源码学习笔记-初始化(一)-概览

 

转自http://www.sandzhang.com/blog/2011/03/30/spring-study-notes-initialization-1/

 

版本:spring-framework-3.0.5.RELEASE
 
很多人看开源框架源代码的时候都不知道从哪里入手,我这里推荐一个最简单的办法,写一个最简单的应用的例子,然后根据这个应用一点一点查看在源码中的运行步骤,这样就能对框架有一个基本的了解,有了这个基本的认识,再去针对不同模块扩展开来仔细研究。
 
本系列主要是学习spring的源码,首先是最简单的使用例子:
[java] view plaincopy
 
  1. ApplicationContext ctx = new ClassPathXmlApplicationContext(  
  2.                 "spring-config.xml");  
  3. FooService foo = (FooService) ctx.getBean("FooService");  

 

我们看第一行初始化了一个ClassPathXmlApplicationContext对象,

注:也可以用FileSystemXmlApplicationContext来加载,两者的区别只是查找配置文件的起始路径不同,一个以classpath为当前路径,一个是直接用文件系统的当前路径,内部没有太大区别。

注2:web工程大家都知道我们配置了ContextLoaderListener,这里暂时不做介绍,后面会有专门的分析,起始主题流程都差不多,详情请参见:从源码看Spring在web工程中的初始化。

请看下面的构造方法,参数是spring配置文件在classpath中的全路径名:


 

[java] view plaincopy
 
  1. public ClassPathXmlApplicationContext(String configLocation) throws BeansException {  
  2.     this(new String[] {configLocation}, truenull);  
  3. }  

可以看到里面调用了另外一个构造方法(如下),其中传递了两个默认参数refresh=true立即刷新,parent=null继承为空,并且把配置文件封装为了一个String数组,这里主要是因为spring是支持多个配置文件的

 

 

[java] view plaincopy
 
  1. public ClassPathXmlApplicationContext(String[] configLocations, boolean refresh, ApplicationContext parent)  
  2.             throws BeansException {  
  3.    
  4.     super(parent);  
  5.     setConfigLocations(configLocations);  
  6.     if (refresh) {  
  7.         refresh();  
  8.     }  
  9. }  

 

我们看这个构造方法的代码:

  • 首先调用了父类的构造函数
  • 调用setConfigLocations设置配置文件位置信息(代码如下)
  • 判断如果refresh为true则调用refresh()方法,refresh方法在AbstractApplicationContext中

setConfigLocations代码:
很简单,主要是检验是否传入参数为空然后赋值给configLocations属性,不过其中有两个小特点可以注意一下:

  1. 并没有直接把传入参数locations直接赋值给属性,而是new了一个String数组,然后循环赋值,这里主要是出于安全考虑避免外面传入的字符串数组变化影响spring内部
  2. 可以看到赋值前有调用了一下resolvePath方法,这个方法实现了一些系统变量的替换,例如路径里可以使用${}加载系统变量值
[java] view plaincopy
 
  1. public void setConfigLocations(String[] locations) {  
  2.     if (locations != null) {  
  3.         Assert.noNullElements(locations,  
  4.                 "Config locations must not be null");  
  5.         this.configLocations = new String[locations.length];  
  6.         for (int i = 0; i < locations.length; i++) {  
  7.             this.configLocations[i] = resolvePath(locations[i]).trim();  
  8.         }  
  9.     } else {  
  10.         this.configLocations = null;  
  11.     }  
  12. }  

下面看refresh刷新方法,这个刷新方法主要是从配置文件加载bean配置的过程,代码如下:

 

[java] view plaincopy
 
  1. public void refresh() throws BeansException, IllegalStateException {  
  2.     // 整个刷新过程是同步的  
  3.     synchronized (this.startupShutdownMonitor) {  
  4.         // 刷新前的准备工作  
  5.         prepareRefresh();  
  6.         // 关闭释放旧的beanFactory创建新的beanFactory,读取配置文件等  
  7.         ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();  
  8.         // 对beanFactory进行一些基本的初始化  
  9.         prepareBeanFactory(beanFactory);  
  10.    
  11.         try {  
  12.             // 下面两行主要用户扩展,处理所有已注册的BeanFactoryPostProcessor,实现在已经加载配置但未初始化bean时对配置进行修改  
  13.             postProcessBeanFactory(beanFactory);  
  14.             invokeBeanFactoryPostProcessors(beanFactory);  
  15.             // 处理所有已注册的BeanPostProcessor,主要用于扩展,实现bean初始化前后的一些定制操作  
  16.             registerBeanPostProcessors(beanFactory);  
  17.    
  18.             // 初始化消息源bean  
  19.             initMessageSource();  
  20.             // 初始化事件监听器集,也有人叫事件监听器的注册表,所有的事件监听器都在这个bean里进行管理  
  21.             initApplicationEventMulticaster();  
  22.             // 主要用于扩展,实现一些特殊bean的初始化,时间点是类似消息源事件监听器集等特殊bean初始化后,普通的bean初始化前  
  23.             onRefresh();  
  24.             // 注册监听器  
  25.             registerListeners();  
  26.             // 初始化其余的非延迟加载的单例bean  
  27.             finishBeanFactoryInitialization(beanFactory);  
  28.    
  29.             // 刷新完成调用LifecycleProcessor的onRefresh方法,并且发布ContextRefreshedEvent事件  
  30.             finishRefresh();  
  31.         } catch (BeansException ex) {  
  32.             // 销毁已经创建的单例bean  
  33.             destroyBeans();  
  34.             // 重新设置active标记  
  35.         cancelRefresh(ex);  
  36.             throw ex;  
  37.         }  
  38.     }  
  39. }  

上面是一个spring初始化的基本流程框架,后面几篇将陆续对其中每一个方法进行详细的分析
posted @ 2013-07-21 15:52  tangpu1987  阅读(798)  评论(0编辑  收藏  举报