zoukankan      html  css  js  c++  java
  • Spring Environment(三)生命周期

    Spring Environment(三)生命周期

    Spring 系列目录(https://www.cnblogs.com/binarylei/p/10198698.html)

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

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

    一、Environment 初始化

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

    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 相关的属性。

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

    二、WEB 环境下 Environment 初始化

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

    2.1 ROOT WebApplicationContext

    (1) XmlWebApplicationContext

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

    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 获取这些属性会提前注入。

    (2) 提前执行 initPropertySources

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

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

  • 相关阅读:
    elasticsearch 安装,以及遇到的问题总结
    Linux/unix 查看端口占用
    openresty 安装
    Hadoop 系列文章(三) 配置部署启动YARN及在YARN上运行MapReduce程序
    Hadoop 系列文章(二) Hadoop配置部署启动HDFS及本地模式运行MapReduce
    Hadoop 系列文章(一) Hadoop 的安装,以及 Standalone Operation 的启动模式测试
    Linux 防火墙相关
    Linux 修改默认的 yum 源
    普通用户开放 sudo 权限
    大数据所有环境变量
  • 原文地址:https://www.cnblogs.com/binarylei/p/10291323.html
Copyright © 2011-2022 走看看