Spring原始碼分析之IoC(二)

JAVA線上發表於2018-09-30

上篇文章講了setConfigLocations方法,本篇繼續往下分析refresh方法。該方法實現在其父類AbstractApplicationContext中,我們進入該方法看下具體實現:

public void refresh() throws BeansException, IllegalStateException {
    synchronized (this.startupShutdownMonitor) {
        // Prepare this context for refreshing.
        prepareRefresh();
        // Tell the subclass to refresh the internal bean factory.
        ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
        // Prepare the bean factory for use in this context.
        prepareBeanFactory(beanFactory);
        try {
            // Allows post-processing of the bean factory in context subclasses.
            postProcessBeanFactory(beanFactory);
            // Invoke factory processors registered as beans in the context.
            invokeBeanFactoryPostProcessors(beanFactory);
            // Register bean processors that intercept bean creation.
            registerBeanPostProcessors(beanFactory);
            // Initialize message source for this context.
            initMessageSource();
            // Initialize event multicaster for this context.
            initApplicationEventMulticaster();
            // Initialize other special beans in specific context subclasses.
            onRefresh();
            // Check for listener beans and register them.
            registerListeners();
            // Instantiate all remaining (non-lazy-init) singletons.
            finishBeanFactoryInitialization(beanFactory);
            // Last step: publish corresponding event.
            finishRefresh();
        }
        catch (BeansException ex) {
            logger.warn("Exception encountered during context initialization - cancelling refresh attempt", ex);
            // Destroy already created singletons to avoid dangling resources.
            destroyBeans();
            // Reset 'active' flag.
            cancelRefresh(ex);
            // Propagate exception to caller.
            throw ex;
        }
        finally {
            // Reset common introspection caches in Spring's core, since we
            // might not ever need metadata for singleton beans anymore...
            resetCommonCaches();
        }
    }
}
複製程式碼

首先會執行prepareRefresh方法,該方法為重新整理上下文做準備,進入該方法:

protected void prepareRefresh() {
    this.startupDate = System.currentTimeMillis();
    this.active.set(true);
    if (logger.isInfoEnabled()) {
        logger.info("Refreshing " + this);
    }
    // Initialize any placeholder property sources in the context environment
    initPropertySources();
    // Validate that all properties marked as required are resolvable
    // see ConfigurablePropertyResolver#setRequiredProperties
    getEnvironment().validateRequiredProperties();
    // Allow for the collection of early ApplicationEvents,
    // to be published once the multicaster is available...
    this.earlyApplicationEvents = new LinkedHashSet<ApplicationEvent>();
}
複製程式碼

該方法首先會設定開始重新整理時間startupDate、活動標誌active,然後執行initPropertySources方法初始化屬性源,進入initPropertySources方法看下:

protected void initPropertySources() {
    // For subclasses: do nothing by default.
}
複製程式碼

該方法是個空方法,子類可以重寫該方法,達到擴充套件目的。

然後,會執行validateRequiredProperties方法:

public void validateRequiredProperties() throws MissingRequiredPropertiesException {
    this.propertyResolver.validateRequiredProperties();
}
複製程式碼
public void validateRequiredProperties() {
    MissingRequiredPropertiesException ex = new MissingRequiredPropertiesException();
    for (String key : this.requiredProperties) {
        if (this.getProperty(key) == null) {
            ex.addMissingRequiredProperty(key);
        }
    }
    if (!ex.getMissingRequiredProperties().isEmpty()) {
        throw ex;
    }
}
複製程式碼

該方法會校驗系統環境中設定的RequiredProperties屬性是否為空,如果為空則丟擲異常。比如說我們設定了屬性值aaa:getEnvironment().setRequiredProperties(“aaa”),但是在系統環境中沒有該屬性則會拋異常。例子:

public class MyApplicationContext extends AbstractXmlApplicationContext {
    public MyApplicationContext () {
        getEnvironment().setRequiredProperties("aaa");
        refresh();
    }
}
複製程式碼
@Test
public void testMyApplicationContext() {
    ApplicationContext applicationContext = new MyApplicationContext();
}
複製程式碼

此時,啟動就會報錯:

org.springframework.core.env.MissingRequiredPropertiesException: The following properties were declared as required but could not be resolved: [aaa]
複製程式碼

我們在系統環境中設定該屬性,就不會丟擲該異常:

@Test
public void testMyApplicationContext() {
    Properties properties = System.getProperties();
    properties.setProperty("aaa", "bbb");
    ApplicationContext applicationContext = new MyApplicationContext();
}
複製程式碼

prepareRefresh方法最後建立一個LinkedHashSet<ApplicationEvent>,並賦值給earlyApplicationEvents,到此prepareRefresh方法就結束了。

如果讀完覺得有收穫的話,歡迎點贊、關注、加公眾號【Java線上】,查閱更多精彩歷史!!!


相關文章