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

天天用心記錄一點點。內容也許不重要,但習慣很重要!

相關文章
相關標籤/搜索