Spring Environment(三)生命周期

Spring Environment(三)生命周期

Spring 系列目录(http://www.javashuo.com/article/p-kqecupyl-bm.html)html

Spring Environment 属性配置管理系列文章:java

  1. Spring Environment(一)API 介绍
  2. Spring Environment(二)源码分析
  3. Spring Environment(三)生命周期

1、Environment 初始化

每一个 ApplicationContext 容器初始化时都会执行 ApplicationContext#refresh() 方法,这个方法的第一步就是 prepareRefresh 方法。web

protected void prepareRefresh() {
    // 1. 初始化一个 Environment 并注入数据源
    initPropertySources();
    // 2. 对必要的属性进行校验
    getEnvironment().validateRequiredProperties();
}

@Override
protected void initPropertySources() {
    // 1. 获取 Environment 实例
    ConfigurableEnvironment env = getEnvironment();
    // 2. 若是是 WEB 环境须要注入 ServletContext 和 servletConfig 数据源
    if (env instanceof ConfigurableWebEnvironment) {
        ((ConfigurableWebEnvironment) env).initPropertySources(this.servletContext, this.servletConfig);
    }
}

AbstractApplicationContext#getEnvironment() 方法默认是建立一个 StandardEnvironment,只注入了 OS 和 JVM 相关的属性。spring

@Override
public ConfigurableEnvironment getEnvironment() {
    if (this.environment == null) {
        this.environment = createEnvironment();
    }
    return this.environment;
}
protected ConfigurableEnvironment createEnvironment() {
    return new StandardEnvironment();
}

2、WEB 环境下 Environment 初始化

WEB 启动时会初始化两个容器,一个是 ROOT WebApplicationContext;一个是 Servlet WebApplicationContext。这两个容器分别是在启动 ContextLoaderListener 和 DispatcherServlet 时初始化的。app

2.1 ROOT WebApplicationContext

(1) XmlWebApplicationContextwebapp

ROOT WebApplicationContext 默认实现类是 XmlWebApplicationContext,是在和 ContextLoader 同级目录的 ContextLoader.properties 文件中配置的。获取其实现类方法以下:ide

protected Class<?> determineContextClass(ServletContext servletContext) {
    String contextClassName = servletContext.getInitParameter(CONTEXT_CLASS_PARAM);
    if (contextClassName != null) {           
        return ClassUtils.forName(contextClassName, ClassUtils.getDefaultClassLoader());            
    } else {
        contextClassName = defaultStrategies.getProperty(WebApplicationContext.class.getName());            
        return ClassUtils.forName(contextClassName, ContextLoader.class.getClassLoader());        
    }
}

XmlWebApplicationContext 的父类 AbstractRefreshableWebApplicationContext 重写了 createEnvironment 方法,返回 StandardServletEnvironment 对象。源码分析

@Override
protected ConfigurableEnvironment createEnvironment() {
    return new StandardServletEnvironment();
}

Spring 调用 refresh 时就会执行 initPropertySources 方法将 ServletContext、ServletConfig 属性注入到 Environment 中,但为了保证 refresh 以前就能够经过 Environment 获取这些属性会提早注入。post

(2) 提早执行 initPropertySourcesui

public WebApplicationContext initWebApplicationContext(ServletContext servletContext) {
    if (this.context == null) {
        this.context = createWebApplicationContext(servletContext);
    }
    if (this.context instanceof ConfigurableWebApplicationContext) {
        ConfigurableWebApplicationContext cwac = (ConfigurableWebApplicationContext) this.context;
        if (!cwac.isActive()) {
            // 1. 配置父容器,若是有
            if (cwac.getParent() == null) {
                ApplicationContext parent = loadParentContext(servletContext);
                cwac.setParent(parent);
            }
            // 2. 配置并启动容器 refresh
            configureAndRefreshWebApplicationContext(cwac, servletContext);
        }
    }
}

protected void configureAndRefreshWebApplicationContext(
    ConfigurableWebApplicationContext wac, ServletContext sc) {      
    // 省略...

    // #refresh 调用以前将 ServletContext 注入到 Environment 中,这样就能够提早使用
    ConfigurableEnvironment env = wac.getEnvironment();
    if (env instanceof ConfigurableWebEnvironment) {
        ((ConfigurableWebEnvironment) env).initPropertySources(sc, null);
    }

    customizeContext(sc, wac);
    wac.refresh();
}

2.2 Servlet WebApplicationContext

DispatcherServlet 继承自 HttpServlet,初始化时会执行对应的 init() 方法,也会建立一个 WebApplicationContext。其默认的实现类也是 XmlWebApplicationContext。

(1) 建立 WebApplicationContext

protected WebApplicationContext initWebApplicationContext() {
    WebApplicationContext rootContext =
            WebApplicationContextUtils.getWebApplicationContext(getServletContext());
    WebApplicationContext wac = null;
    // 省略... 
    if (wac == null) {
        // 建立 WebApplicationContext
        wac = createWebApplicationContext(rootContext);
    }
    if (!this.refreshEventReceived) {
        synchronized (this.onRefreshMonitor) {
            onRefresh(wac);
        }
    }
    return wac;
}

protected WebApplicationContext createWebApplicationContext(@Nullable ApplicationContext parent) {
    Class<?> contextClass = getContextClass();
    ConfigurableWebApplicationContext wac =
            (ConfigurableWebApplicationContext) BeanUtils.instantiateClass(contextClass);
    // 设置 Environment 环境变量
    wac.setEnvironment(getEnvironment());
    wac.setParent(parent);
    String configLocation = getContextConfigLocation();
    if (configLocation != null) {
        wac.setConfigLocation(configLocation);
    }
    configureAndRefreshWebApplicationContext(wac);
    return wac;
}

(2) 提早执行 initPropertySources

和 ROOT WebApplicationContext 相似,也会提早将 ServletContext 和 ServletConfig 提早注入到 Environment 变量中。

protected void configureAndRefreshWebApplicationContext(ConfigurableWebApplicationContext wac) {
    ConfigurableEnvironment env = wac.getEnvironment();
    if (env instanceof ConfigurableWebEnvironment) {
        ((ConfigurableWebEnvironment) env).initPropertySources(getServletContext(), getServletConfig());
    }

    postProcessWebApplicationContext(wac);
    applyInitializers(wac);
    wac.refresh();
}

天天用心记录一点点。内容也许不重要,但习惯很重要!

相关文章
相关标签/搜索