您的位置:首页 > 编程语言 > Java开发

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

2013-07-12 15:24 260 查看
转自http://www.sandzhang.com/blog/2011/03/30/spring-study-notes-initialization-1/

版本:spring-framework-3.0.5.RELEASE

很多人看开源框架源代码的时候都不知道从哪里入手,我这里推荐一个最简单的办法,写一个最简单的应用的例子,然后根据这个应用一点一点查看在源码中的运行步骤,这样就能对框架有一个基本的了解,有了这个基本的认识,再去针对不同模块扩展开来仔细研究。

本系列主要是学习spring的源码,首先是最简单的使用例子:

[java]
view plaincopyprint?

ApplicationContext ctx = new ClassPathXmlApplicationContext( 

                "spring-config.xml"); 

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中的全路径名:

[java]
view plaincopyprint?

public ClassPathXmlApplicationContext(String configLocation)
throws BeansException { 
    this(new String[] {configLocation},
true, null); 



public ClassPathXmlApplicationContext(String configLocation) throws BeansException {
this(new String[] {configLocation}, true, null);
}

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

[java]
view plaincopyprint?

public ClassPathXmlApplicationContext(String[] configLocations,
boolean refresh, ApplicationContext parent) 

            throws BeansException { 

  
    super(parent); 
    setConfigLocations(configLocations); 
    if (refresh) { 
        refresh(); 
    } 


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属性,不过其中有两个小特点可以注意一下:

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

[java]
view plaincopyprint?

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; 
    } 


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配置的过程,代码如下:

[java]
view plaincopyprint?

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; 
        } 
    } 


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初始化的基本流程框架,后面几篇将陆续对其中每一个方法进行详细的分析
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  spring 源代码