• prepareRefresh方法源码跟踪


    看这篇文章之前可以先了解之前的跟踪流程,https://www.jianshu.com/p/4934233f0ead

    代码过宽,可以shift + 鼠标滚轮 左右滑动查看

    AbstractApplicationContext类中refresh()方法的第一个调用方法prepareRefresh()的跟踪。

    @Override
    public void refresh() throws BeansException, IllegalStateException {
        synchronized (this.startupShutdownMonitor) {
            
            // Prepare this context for refreshing.
            // 准备上下文的刷新
            prepareRefresh();
            ···
     }
    

    直接进入。

    prepareRefresh(零)

    prepareRefresh方法在AbstractApplicationContext类中,此类是XmlWebApplicationContext的上层父类

    // Prepare this context for refreshing.
    // 准备 context 的刷新
    prepareRefresh();
    
    /**
     * Prepare this context for refreshing, setting its startup date and
     * active flag as well as performing any initialization of property sources.
     *
     * 准备 context 的刷新,设置他的启动数据、激活标志以及执行一些属性源的初始化
     */
    protected void prepareRefresh() {
        
        // 启动时间
        this.startupDate = System.currentTimeMillis();
        
        // 此 context 是否已经被关闭
        this.closed.set(false);
        
        // active 表示这个 context 当前是否处于活跃状态
        this.active.set(true);
    
        if (logger.isInfoEnabled()) {
            logger.info("Refreshing " + this);
        }
    
        // Initialize any placeholder property sources in the context environment
        
        // 1.在 context 的 environment 中初始化占位符属性源
        initPropertySources();
    
        // Validate that all properties marked as required are resolvable
        // see ConfigurablePropertyResolver#setRequiredProperties
        
        // 验证所有被标记为必要的属性是否可解析,如果有遗失属性则不能解析并抛出异常,
        // 可以参考setRequiredProperties方法
        getEnvironment().validateRequiredProperties();
    
        // Allow for the collection of early ApplicationEvents,
        // to be published once the multicaster is available...
        
        // 一旦有可利用的广播,允许早期的ApplicationEvents集合被发布
        this.earlyApplicationEvents = new LinkedHashSet<ApplicationEvent>();
    }
    

    1.initPropertySources

    跟踪标记1的方法

    initPropertySources 方法在 AbstractApplicationContext 中默认不做任何事情,具体业务流程由其子类覆盖完成,也就是在 AbstractRefreshableWebApplicationContext 类中进行,AbstractRefreshableWebApplicationContext 是XmlWebApplicationContext的父类

    // Initialize any placeholder property sources in the context environment
    // 1.在 context environment 中初始化占位符属性源
    initPropertySources();
    
    /**
    * {@inheritDoc}
    * <p>Replace {@code Servlet}-related property sources.
    *
    * 替换Servlet相关的属性源
    */
    @Override
    protected void initPropertySources() {
        
        // 在设置 root web application context 的 contextConfigLocation 属性时,已经调用过此方法。
        // 在ContextLoader类中的configureAndRefreshWebApplicationContext方法中,
        // 又调用了 initPropertySources 方法对 environment 进行了初始化
        // 此时 environment 已存在,直接返回。
        ConfigurableEnvironment env = getEnvironment();
        if (env instanceof ConfigurableWebEnvironment) {
            
            // 1.1初始化属性源
            ((ConfigurableWebEnvironment) env).initPropertySources(this.servletContext, this.servletConfig);
        }
    }
    

    1.1 initPropertySources

    跟踪标记1.1的方法

    env(也就是environment对象)调用了initPropertySources方法,该方法的具体实现由ConfigurableWebEnvironment的子类StandardServletEnvironment进行。

    environment对象是StandardServletEnvironment类的实例。

    //1.1初始化属性源
    ((ConfigurableWebEnvironment) env).initPropertySources(this.servletContext, this.servletConfig);
    
    
    /**
    * Replace any {@linkplain
    * org.springframework.core.env.PropertySource.StubPropertySource stub property source}
    * instances acting as placeholders with real servlet context/config property sources
    * using the given parameters.
    * 
    * 用真正的servlet context/config 属性源来替换作为占位符存在的 stub 属性源
    */
    @Override
    public void initPropertySources(ServletContext servletContext, ServletConfig servletConfig) {
        
        // 工具类来初始化属性源,进入这个方法
    	WebApplicationContextUtils.initServletPropertySources(getPropertySources(), servletContext, servletConfig);
    }
    
    
    /**
    * Replace {@code Servlet}-based {@link StubPropertySource stub property sources} with
    * actual instances populated with the given {@code servletContext} and
    * {@code servletConfig} objects.
    * <p>This method is idempotent with respect to the fact it may be called any number
    * of times but will perform replacement of stub property sources with their
    * corresponding actual property sources once and only once.
    *
    * 用<由servletContext和servletConfig对象填充的>实例去替换基于servlet的 stub 属性源。
    * 这个方法幂等遵守这个情况:他可能被调用任意次数,但是有且仅会执行一次 stub 属性源与它所匹配
    * 的实际属性源的替换
    */
    public static void initServletPropertySources(
        MutablePropertySources propertySources, ServletContext servletContext, ServletConfig servletConfig) {
    
        Assert.notNull(propertySources, "'propertySources' must not be null");
        
        // 此条件第三项不通过。
        // 在ContextLoader类的configureAndRefreshWebApplicationContext方法中
        // 已调用过一次StandardServletEnvironment对象的initPropertySources方法,
        // 完成了根属性源的替换,所以第三项不再通过
        if (servletContext != null && propertySources.contains(StandardServletEnvironment.SERVLET_CONTEXT_PROPERTY_SOURCE_NAME) &&
            propertySources.get(StandardServletEnvironment.SERVLET_CONTEXT_PROPERTY_SOURCE_NAME) instanceof StubPropertySource) {
            propertySources.replace(StandardServletEnvironment.SERVLET_CONTEXT_PROPERTY_SOURCE_NAME,
                                    new ServletContextPropertySource(StandardServletEnvironment.SERVLET_CONTEXT_PROPERTY_SOURCE_NAME, servletContext));
        }
        
        //此处servletConfig为空,所以跳过
        if (servletConfig != null && propertySources.contains(StandardServletEnvironment.SERVLET_CONFIG_PROPERTY_SOURCE_NAME) &&
            propertySources.get(StandardServletEnvironment.SERVLET_CONFIG_PROPERTY_SOURCE_NAME) instanceof StubPropertySource) {
            propertySources.replace(StandardServletEnvironment.SERVLET_CONFIG_PROPERTY_SOURCE_NAME,
                                    new ServletConfigPropertySource(StandardServletEnvironment.SERVLET_CONFIG_PROPERTY_SOURCE_NAME, servletConfig));
        }
    }
    

    prepareRefresh方法只有这么多,接下来跟踪obtainFreshBeanFactory方法:

    https://www.jianshu.com/p/144af98965d9

    总结

    • 设置 context 关闭状态、激活标志等
    • 在 context 的 environment 中初始化占位符属性源,用真正的servlet context/config 属性源来替换作为占位符存在的 stub 属性源
    • 验证所有被标记为必要的属性是否可解析
  • 相关阅读:
    小米范工具系列之一:小米范 web查找器
    不同格式的ip 统一转成ip列表
    Educational Codeforces Round 32
    离散化方式
    线段树合并与分裂
    HDU1074
    容斥原理
    模板
    HDU1024 Max Sum Plus Plus
    CSA Round #56
  • 原文地址:https://www.cnblogs.com/feng-jq/p/10282179.html
Copyright © 2020-2023  润新知