今天看了一下Spring Boot的run函數運行過程,發現它調用了Context中的refresh函數。所以先分析一下Spring context的refresh過程,然后再分析Spring boot中run的流程。
首先我們找到spring-context組件的AbstractApplicationContext類下的refresh函數:
@Override 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) { if (logger.isWarnEnabled()) { 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() { // Switch to active. this.startupDate = System.currentTimeMillis(); this.closed.set(false); this.active.set(true); ...... // Initialize any placeholder property sources in the context environment. initPropertySources(); // Validate that all properties marked as required are resolvable: // see ConfigurablePropertyResolver#setRequiredProperties getEnvironment().validateRequiredProperties(); // Store pre-refresh ApplicationListeners... if (this.earlyApplicationListeners == null) { this.earlyApplicationListeners = new LinkedHashSet<>(this.applicationListeners); } else { // Reset local application listeners to pre-refresh state. this.applicationListeners.clear(); this.applicationListeners.addAll(this.earlyApplicationListeners); } // Allow for the collection of early ApplicationEvents, // to be published once the multicaster is available... this.earlyApplicationEvents = new LinkedHashSet<>(); }
可以看到,這個函數做了一些准備工作,記錄了refresh的開始時間,調用了留給子類重寫的initPropertySources()函數。
驗證了環境中必要的參數,並且將earlyListeners加入到應用程序的監聽器列表中。
obtainFreshBeanFactory()
protected ConfigurableListableBeanFactory obtainFreshBeanFactory() { refreshBeanFactory(); return getBeanFactory(); }
可以看見,refreshBeanFactory()和getBeanFactory()都是abstract函數,這兩個函數設計出來就是為了讓子類重寫,根據子類實現具體功能,從函數名可以推斷出這兩個函數一個是用來初始化beanFactory,另外一個則是拿到beanFactory的實例,我們以AbstractRefreshableApplicationContext類的代碼為例:
refreshBeanFactory:
@Override protected final void refreshBeanFactory() throws BeansException { if (hasBeanFactory()) {//如果beanFactory已經被初始化過,則在此銷毀 destroyBeans(); closeBeanFactory(); } try {//這里其實就是new了一個DefaultListableBeanFactory DefaultListableBeanFactory beanFactory = createBeanFactory(); beanFactory.setSerializationId(getId()); //客制化beanFactory,例如設置能否循環引用,能否重寫bean等 customizeBeanFactory(beanFactory); //將xml中的bean定義加載到spring-core的注冊中心中 loadBeanDefinitions(beanFactory); //設置beanFactory,供getBeanFactory取得 synchronized (this.beanFactoryMonitor) { this.beanFactory = beanFactory; } } catch (IOException ex) { throw new ApplicationContextException("I/O error parsing bean definition source for " + getDisplayName(), ex); } }
getBeanFactory:不難想象,這個函數從this類中拿到beanFactory實例並返回。
prepareBeanFactory(beanFactory)
篇幅原因就不貼這部分代碼,實在太長,這個函數主要做了如下幾件事:
1. 設置了beanFactory的classloader
2. 設置了SpEL的解析器
3. 設置了PropertyEditor,這個是用來將xml里面的占位符解析成具體值的,例如xml里面寫<... value="${predefined-var}"/>,在PropertyEditor可以將${predefined-var}解析為某個具體值,並且到時候生成的beanDefinition對應的field就是這個具體的值。這一步會發生在xml被轉換為beanDefinition之前
4. 增加ApplicationContextAwareProcessor的BeanPostProcessor,這個是為了讓實現了ApplicationContextAware接口的bean在初始化后自身被注入當前的ApplicationContext,實現對自己所在的Context的感知
5. 忽略下述接口的依賴注入:
EnvironmentAware.class
EmbeddedValueResolverAware.class
ResourceLoaderAware.class
ApplicationEventPublisherAware.class
MessageSourceAware.class
ApplicationContextAware.class
觀察上述接口的特征,發現這些都是Aware系列接口,用於使Bean感知環境中的參數(例如當前Context)。自動裝配不會對這些接口進行處理,實際上實現了這些接口的類會在Spring中有專門的函數進行處理。
6. 對於一些特定的接口實現,定義默認的注入值:
BeanFactory.class
ResourceLoader.class
ApplicationEventPublisher.class
ApplicationContext.class
這些接口是用來獲取關於Spring本身相關的信息的,例如Spring本身的BeanFactory等。
7. 注冊一些環境相關的bean,例如systemProperties、systemEnvironment和environment
postProcessBeanFactory(beanFactory)
這個函數實際上是空的:
/** * Modify the application context's internal bean factory after its standard * initialization. All bean definitions will have been loaded, but no beans * will have been instantiated yet. This allows for registering special * BeanPostProcessors etc in certain ApplicationContext implementations. * @param beanFactory the bean factory used by the application context */ protected void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) { }
通過上面的注釋,我們可以知道,當所有的xml已經被載入並且產生了對應的beanDefinition時,這個函數將會被調用,此時bean的實例都沒有產生,在此處可以對beanDefinition的屬性進行修改、抑或是注冊特別的beanPostProcessor用於對實例化的bean做最終處理。
這里函數留空是為了讓用戶能夠子類化,然后在里面寫入自己需要的修改,典型的模板設計模式
invokeBeanFactoryPostProcessors(beanFactory)
調用所有在容器中注冊的BeanFactoryPostProcessor
registerBeanPostProcessors(beanFactory)
注冊BeanPostProcessors,將所有在xml中定義的beanPostProcessors加入到當前BeanFactory的列表,以便在getBean的時候調用。
initMessageSource()
初始化消息源
initApplicationEventMulticaster()
protected void initApplicationEventMulticaster() { ConfigurableListableBeanFactory beanFactory = getBeanFactory(); if (beanFactory.containsLocalBean(APPLICATION_EVENT_MULTICASTER_BEAN_NAME)) { this.applicationEventMulticaster = beanFactory.getBean(APPLICATION_EVENT_MULTICASTER_BEAN_NAME, ApplicationEventMulticaster.class); if (logger.isTraceEnabled()) { logger.trace("Using ApplicationEventMulticaster [" + this.applicationEventMulticaster + "]"); } } else { this.applicationEventMulticaster = new SimpleApplicationEventMulticaster(beanFactory); beanFactory.registerSingleton(APPLICATION_EVENT_MULTICASTER_BEAN_NAME, this.applicationEventMulticaster); if (logger.isTraceEnabled()) { logger.trace("No '" + APPLICATION_EVENT_MULTICASTER_BEAN_NAME + "' bean, using " + "[" + this.applicationEventMulticaster.getClass().getSimpleName() + "]"); } } }
通過Spring容器得到一個applicationEventMulticaster,如果Spring容器沒有定義,則創建SimpleApplicationEventMulticaster作為applicationEventMulticaster。
通過SimpleApplicationEventMulticaster的代碼我們也能推斷出這個類的作用,就是向Context里面的EventListener發布消息:
public void multicastEvent(final ApplicationEvent event, @Nullable ResolvableType eventType) { ResolvableType type = (eventType != null ? eventType : resolveDefaultEventType(event)); Executor executor = getTaskExecutor(); //將當前的事件event發送給當前Context的每一個Listener for (ApplicationListener<?> listener : getApplicationListeners(event, type)) { //如果有executor則使用executor執行 if (executor != null) { executor.execute(() -> invokeListener(listener, event)); } else { //否則直接在當前線程執行 invokeListener(listener, event); } } }
onRefresh()
這是模板方法,留給子類實現並執行想要的操作
registerListeners()
這一步將注冊Listener,供前面initApplicationEventMulticaster注冊的EventMulticaster進行廣播,代碼如下:
protected void registerListeners() { // Register statically specified listeners first. for (ApplicationListener<?> listener : getApplicationListeners()) { getApplicationEventMulticaster().addApplicationListener(listener); } // Do not initialize FactoryBeans here: We need to leave all regular beans // uninitialized to let post-processors apply to them! String[] listenerBeanNames = getBeanNamesForType(ApplicationListener.class, true, false); for (String listenerBeanName : listenerBeanNames) { getApplicationEventMulticaster().addApplicationListenerBean(listenerBeanName); } // Publish early application events now that we finally have a multicaster... Set<ApplicationEvent> earlyEventsToProcess = this.earlyApplicationEvents; this.earlyApplicationEvents = null; if (earlyEventsToProcess != null) { for (ApplicationEvent earlyEvent : earlyEventsToProcess) { getApplicationEventMulticaster().multicastEvent(earlyEvent); } } }
這段代碼將靜態注冊的Listener和Spring中注冊的Listener bean都添加到EventMulticaster中,這樣從EventMulticaster中發布的消息,每個Listener都能監聽到,典型的觀察者模式。
值得注意的是,Context中包含earlyApplicationEvents,所有的Listener就緒后,會先接收到這個事件。
finishBeanFactoryInitialization(beanFactory)
通過上面的注釋:Instantiate all remaining (non-lazy-init) singletons.
我們可以知道,這個方法初始化所有的非懶加載單例實例,代碼很復雜,后面會開一個專題分析這段代碼的。
finishRefresh()
從函數名可以知道這個是完成刷新,代碼如下:
protected void finishRefresh() { // Clear context-level resource caches (such as ASM metadata from scanning). clearResourceCaches(); // Initialize lifecycle processor for this context. initLifecycleProcessor(); // Propagate refresh to lifecycle processor first. getLifecycleProcessor().onRefresh(); // Publish the final event. publishEvent(new ContextRefreshedEvent(this)); // Participate in LiveBeansView MBean, if active. LiveBeansView.registerApplicationContext(this); }
實際上它:
1. 清空了資源緩存
2. 初始化了生命周期處理器,用於處理Bean生命周期
3. 使用生命周期處理器傳播刷新事件
4. 在Context內發布刷新事件
5. 將本Context注冊到ListBeansView中
至此,Context的refresh分析完畢,下一部該分析Spring Boot的run進行了什么操作了。