prepareRefresh方法源碼跟蹤

看這篇文章以前能夠先了解以前的跟蹤流程,https://www.jianshu.com/p/4934233f0eadjava

代碼過寬,能夠shift + 鼠標滾輪 左右滑動查看web

AbstractApplicationContext類中refresh()方法的第一個調用方法prepareRefresh()的跟蹤。spring

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

直接進入。app

prepareRefresh(零)

prepareRefresh方法在AbstractApplicationContext類中,此類是XmlWebApplicationContext的上層父類ide

// 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的父類ui

// 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的方法this

env(也就是environment對象)調用了initPropertySources方法,該方法的具體實現由ConfigurableWebEnvironment的子類StandardServletEnvironment進行。code

environment對象是StandardServletEnvironment類的實例。orm

//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 屬性源
  • 驗證全部被標記爲必要的屬性是否可解析
相關文章
相關標籤/搜索