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

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

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

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

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

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

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


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

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

  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. }  
public ClassPathXmlApplicationContext(String[] configLocations, boolean refresh, ApplicationContext parent)
            throws BeansException {
 
    super(parent);
    setConfigLocations(configLocations);
    if (refresh) {
        refresh();
    }
}

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

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

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

  1. 并没有直接把传入参数locations直接赋值给属性,而是new了一个String数组,然后循环赋值,这里主要是出于安全考虑避免外面传入的字符串数组变化影响spring内部
  2. 可以看到赋值前有调用了一下resolvePath方法,这个方法实现了一些系统变量的替换,例如路径里可以使用${}加载系统变量值
  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. }  
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;
    }
}

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

  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. }  
public void refresh() throws BeansException, IllegalStateException {
    // 整个刷新过程是同步的
    synchronized (this.startupShutdownMonitor) {
        // 刷新前的准备工作
        prepareRefresh();
        // 关闭释放旧的beanFactory创建新的beanFactory,读取配置文件等
        ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
        // 对beanFactory进行一些基本的初始化
        prepareBeanFactory(beanFactory);
 
        try {
            // 下面两行主要用户扩展,处理所有已注册的BeanFactoryPostProcessor,实现在已经加载配置但未初始化bean时对配置进行修改
            postProcessBeanFactory(beanFactory);
            invokeBeanFactoryPostProcessors(beanFactory);
            // 处理所有已注册的BeanPostProcessor,主要用于扩展,实现bean初始化前后的一些定制操作
            registerBeanPostProcessors(beanFactory);
 
            // 初始化消息源bean
            initMessageSource();
            // 初始化事件监听器集,也有人叫事件监听器的注册表,所有的事件监听器都在这个bean里进行管理
            initApplicationEventMulticaster();
            // 主要用于扩展,实现一些特殊bean的初始化,时间点是类似消息源事件监听器集等特殊bean初始化后,普通的bean初始化前
            onRefresh();
            // 注册监听器
            registerListeners();
            // 初始化其余的非延迟加载的单例bean
            finishBeanFactoryInitialization(beanFactory);
 
            // 刷新完成调用LifecycleProcessor的onRefresh方法,并且发布ContextRefreshedEvent事件
            finishRefresh();
        } catch (BeansException ex) {
            // 销毁已经创建的单例bean
            destroyBeans();
            // 重新设置active标记
        cancelRefresh(ex);
            throw ex;
        }
    }
}

上面是一个spring初始化的基本流程框架,后面几篇将陆续对其中每一个方法进行详细的分析
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值