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(); }
天天用心记录一点点。内容也许不重要,但习惯很重要!