Spring源码分析专题 —— IOC容器启动过程(下篇)

栏目: 编程工具 · 发布时间: 6年前

内容简介:声明1.建议先阅读2.强烈建议阅读过程中要参照调用过程图,每篇都有对应的调用过程图

声明

1.建议先阅读 《Spring源码分析专题 —— 阅读指引》

2.强烈建议阅读过程中要参照调用过程图,每篇都有对应的调用过程图

3.写文不易,转载请标明出处

前言

Spring IOC 容器的启动过程是「 定位 -> 加载 -> 注册 -> 实例化 」,前边已经讲解了最重要的「加载」与「注册」过程(「实例化」的内容将在依赖注入的章节讲解),本篇的主题是对「上篇」「中篇」的补充,定位的详细过程会在本篇中讲解,之后如果有必要还会在本篇中补充其他的一些细节内容。

定位

调用过程图↓↓↓

Spring源码分析专题 —— IOC容器启动过程(下篇)

关于前边的调用过程我们略过,直接来到图中的入口: ContextLoader 的 configureAndRefreshWebApplicationContext 方法。

protected void configureAndRefreshWebApplicationContext(ConfigurableWebApplicationContext wac, ServletContext sc) {
    if (ObjectUtils.identityToString(wac).equals(wac.getId())) {
        // The application context id is still set to its original default value
        // -> assign a more useful id based on available information
        String idParam = sc.getInitParameter(CONTEXT_ID_PARAM);
        if (idParam != null) {
            wac.setId(idParam);
        }
        else {
            // Generate default id...
            wac.setId(ConfigurableWebApplicationContext.APPLICATION_CONTEXT_ID_PREFIX +
                    ObjectUtils.getDisplayString(sc.getContextPath()));
        }
    }

    wac.setServletContext(sc);
        /**
         * [note-by-leapmie]
         * CONFIG_LOCATION_PARAM = "contextConfigLocation"
         * 对应的含义是读取web.xml中contextConfigLocation的值
         */
        String configLocationParam = sc.getInitParameter(CONFIG_LOCATION_PARAM);
        if (configLocationParam != null) {
        wac.setConfigLocation(configLocationParam);
    }

    // The wac environment's #initPropertySources will be called in any case when the context
    // is refreshed; do it eagerly here to ensure servlet property sources are in place for
    // use in any post-processing or initialization that occurs below prior to #refresh
    ConfigurableEnvironment env = wac.getEnvironment();
    if (env instanceof ConfigurableWebEnvironment) {
        ((ConfigurableWebEnvironment) env).initPropertySources(sc, null);
    }

    customizeContext(sc, wac);
    /** [note-by-leapmie] 调用容器的refresh()方法,此处wac对应的类是XmlWebApplicationContext **/
    wac.refresh();
}

在「上篇」 中我们有看过这个方法,当时我们关心的是最后一行 wac.refresh() ,这次我们关心的是 wac.setConfigLocation(configLocationParam); 。configLocationParam 的值是调用 sc.getInitParameter(CONFIG_LOCATION_PARAM); 获取的,CONFIG_LOCATION_PARAM的值是 "contextConfigLocation" ,对于 "contextConfigLocation" 有印象吗?回顾我们的 web.xml 配置文件中可以看到,我们配置了一个 <context-param> 上下文参数,这个参数名便是 contextConfigLocation , 而其值是便是我们自定义的 Spring 配置文件路径

<web-app>

    <context-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>classpath:spring.xml</param-value>
    </context-param>

    <!-- ContextLoaderListener -->
    <listener>
        <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
    </listener>

    <!-- DispatcherServlet -->
    ...
</web-app>

如果有兴趣还可以继续深入查看 setConfigLocation 的处理逻辑,其实现过程是在 AbstractRefreshableConfigApplicationContext 类中,通过代码可知道配置文件支持的分隔符有 ,; \t\n ,这里我们不再占用篇幅深入讲解了。

接下来我们直接分析 XmlWebApplicationContext 的 loadBeanDefinitions(XmlBeanDefinitionReader) 方法(忘记调用路线的可以看回「上篇」中的调用过程图复习一下)

protected void loadBeanDefinitions(XmlBeanDefinitionReader reader) throws IOException {
    /** [note-by-leapmie] 获取配置文件位置*/
    String[] configLocations = getConfigLocations();
    if (configLocations != null) {
        for (String configLocation : configLocations) {
            /** [note-by-leapmie] 实际是调用XmlBeanDefinitionReader的loadBeanDefinitions方法 **/
            reader.loadBeanDefinitions(configLocation);
        }
    }
}

这个方法我们在前边也是看过的,当时我们只关注 reader.loadBeanDefinitions(configLocation); 这一行,这次我们关注第一行 String[] configLocations = getConfigLocations(); ,从方法的字面意思就很容易理解它的作用——获取配置位置,很明显这就是我们的「定位」过程。

getConfigLocations 的实现方法是在其父类 AbstractRefreshableConfigApplicationContext 中

protected String[] getConfigLocations() {
    return (this.configLocations != null ? this.configLocations : getDefaultConfigLocations());
}

这个方法的意思是,当容器中的 configLocations 变量为空时则调用 getDefaultConfigLocations, 当不为空时直接返回容器中的 configLocations 。我们先看一看 getDefaultConfigLocations 方法

protected String[] getDefaultConfigLocations() {
    if (getNamespace() != null) {
        return new String[] {DEFAULT_CONFIG_LOCATION_PREFIX + getNamespace() + DEFAULT_CONFIG_LOCATION_SUFFIX};
    }
    else {
        return new String[] {DEFAULT_CONFIG_LOCATION};
    }
}

DEFAULT_CONFIG_LOCATION 的定义是

/** Default config location for the root context. */
public static final String DEFAULT_CONFIG_LOCATION = "/WEB-INF/applicationContext.xml";

/WEB-INF/applicationContext.xml 便是我们再熟悉不过的 Spring 默认的配置文件路径与文件名。

而当我们再 web.xml 配置了 contextConfigLocation ,Spring则会读取我们的自定义 Spring 配置文件。至此,关于「定位」的过程已经完整讲解完毕。

[目录]

[上一篇]Spring源码分析专题 —— IOC容器启动过程(中篇)

[[下一篇]Spring源码分析专题 —— IOC容器依赖注入]


以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

轻资产创业

轻资产创业

蔡余杰 / 广东人民出版社 / 2017-11 / 45.00元

在互联网时代,资金和资源已经不是制约创业的关键因素。如今即便没有充足的资金和资产做后盾,创业梦依旧可以成为现实。相信轻资产创业模式能够帮助众多经营管理者和创业者实现管理与创业的梦想。 轻资产创业存在误区,如何跨过? 如何巧用四大模式让自媒体创业落地? 如何用一个点子引发创意型创业? 如何利用电商平台实现流量为王的营销型创业? 如何巧用知识节点做好知识产型创业? ......一起来看看 《轻资产创业》 这本书的介绍吧!

随机密码生成器
随机密码生成器

多种字符组合密码

HEX HSV 转换工具
HEX HSV 转换工具

HEX HSV 互换工具