Spring 系列目錄(http://www.javashuo.com/article/p-kqecupyl-bm.html)html
Spring Environment 屬性配置管理系列文章:java
每一個 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(); }
WEB 啓動時會初始化兩個容器,一個是 ROOT WebApplicationContext;一個是 Servlet WebApplicationContext。這兩個容器分別是在啓動 ContextLoaderListener 和 DispatcherServlet 時初始化的。app
(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(); }
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(); }
天天用心記錄一點點。內容也許不重要,但習慣很重要!