Spring原始碼分析之IoC(二)
上篇文章講了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線上】,查閱更多精彩歷史!!!