一、Spring 容器高層視圖
Spring 啟動時讀取應用程序提供的Bean配置信息,並在Spring容器中生成一份相應的Bean配置注冊表,然后根據這張注冊表實例化Bean,裝配號Bean之間的依賴關系,為上層應用提供准備就緒的運行環境。
二、內部工作機制
該圖描述了Spring容器從加載配置文件到創建出一個完整Bean的作業流程:
1、ResourceLoader從存儲介質中加載Spring配置信息,並使用Resource表示這個配置文件的資源;
2、BeanDefinitionReader讀取Resource所指向的配置文件資源,然后解析配置文件。配置文件中每一個<bean>解析成一個BeanDefinition對象,並保存到BeanDefinitionRegistry中;
3、容器掃描BeanDefinitionRegistry中的BeanDefinition,使用Java的反射機制自動識別出Bean工廠后處理后器(實現BeanFactoryPostProcessor接口)的Bean,然后調用這些Bean工廠后處理器對BeanDefinitionRegistry中的BeanDefinition進行加工處理。主要完成以下兩項工作:
1)對使用到占位符的<bean>元素標簽進行解析,得到最終的配置值,這意味對一些半成品式的BeanDefinition對象進行加工處理並得到成品的BeanDefinition對象;
2)對BeanDefinitionRegistry中的BeanDefinition進行掃描,通過Java反射機制找出所有屬性編輯器的Bean(實現java.beans.PropertyEditor接口的Bean),並自動將它們注冊到Spring容器的屬性編輯器注冊表中(PropertyEditorRegistry);
4.Spring容器從BeanDefinitionRegistry中取出加工后的BeanDefinition,並調用InstantiationStrategy着手進行Bean實例化的工作;
5.在實例化Bean時,Spring容器使用BeanWrapper對Bean進行封裝,BeanWrapper提供了很多以Java反射機制操作Bean的方法,它將結合該Bean的BeanDefinition以及容器中屬性編輯器,完成Bean屬性的設置工作;
6.利用容器中注冊的Bean后處理器(實現BeanPostProcessor接口的Bean)對已經完成屬性設置工作的Bean進行后續加工,直接裝配出一個准備就緒的Bean。
Spring容器確實堪稱一部設計精密的機器,其內部擁有眾多的組件和裝置。Spring的高明之處在於,它使用眾多接口描繪出了所有裝置的藍圖,構建好Spring的骨架,繼而通過繼承體系層層推演,不斷豐富,最終讓Spring成為有血有肉的完整的框架。所以查看Spring框架的源碼時,有兩條清晰可見的脈絡:
1)接口層描述了容器的重要組件及組件間的協作關系;
2)繼承體系逐步實現組件的各項功能。
接口層清晰地勾勒出Spring框架的高層功能,框架脈絡呼之欲出。有了接口層抽象的描述后,不但Spring自己可以提供具體的實現,任何第三方組織也可以提供不同實現, 可以說Spring完善的接口層使框架的擴展性得到了很好的保證。縱向繼承體系的逐步擴展,分步驟地實現框架的功能,這種實現方案保證了框架功能不會堆積在某些類的身上,造成過重的代碼邏輯負載,框架的復雜度被完美地分解開了。
Spring組件按其所承擔的角色可以划分為兩類:
1)物料組件:Resource、BeanDefinition、PropertyEditor以及最終的Bean等,它們是加工流程中被加工、被消費的組件,就像流水線上被加工的物料;
2)加工設備組件:ResourceLoader、BeanDefinitionReader、BeanFactoryPostProcessor、InstantiationStrategy以及BeanWrapper等組件像是流水線上不同環節的加工設備,對物料組件進行加工處理。
三、Spring容器-ApplicationContext的啟動過程
ApplicationContext內部封裝了一個BeanFactory對象,來實現對容器的操作,初始化完成之后,BeanFactory封裝了bean的信息,而ApplicationContext通過訪問這個對象獲取bean的對象信息(BeanDefinition/Bean對象,都是由BeanFactory實際創建並管理的),為了實現接口的統一,ApplicationContext也實現了一系列的BeanFactory接口(可以說ApplicationContext對BeanFactory對象實現一種代理)。ApplicationContext建立在BeanFactory的基礎之上,對配置對象的管理最終還是交於一個DefaultListableBeanFactory來完成(裝配地址/訪問等),而ApplicationContext在應用這個DefaultListableBeanFactory對象的基礎上,不僅實現了BeanFactory接口提供的功能方法,並且黏合了一些面向應用的功能,如資源/國際化支持/框架事件支持等,並且將一些原先需要手動設置到BeanFactory的屬性通過配置文件中配置的形式代替(如工廠后處理器BeanPostProcessor/InstantiationAwareBeanPostProcessor)
同樣,因為對於BeanDefinition和bean對象的管理是由上下文持有的beanfactory對象完成的,用戶不需要擁有這樣的接口,因此,ApplicationContext的接口體系中並沒有BeanDefinitionRegistry,SingletonBeanRegistry以及AutowireCapableBeanFactory接口(ApplicationContext可以訪問一些接口方法在上述接口中也定義,但這些方法提供者為BeanFactory體系中的其他接口,BeanFactory接口體系中的接口之間有重復定義方法的)。
內部工作機制(Spring容器ApplicationContext的初始化)
(一) 首先來看創建ApplicationContext ,以ClassPathXmlApplicationContext為例:
ApplicationContext = new ClassPathXmlApplicationContext(xmlPath);
源碼如下:
public class ClassPathXmlApplicationContext extends AbstractXmlApplicationContext { public ClassPathXmlApplicationContext(String configLocation) throws BeansException { this(new String[] {configLocation}); } public ClassPathXmlApplicationContext(String[] configLocations) throws BeansException { this(configLocations, (ApplicationContext) null); } //。。。。。。省略幾個重載的構造函數 public ClassPathXmlApplicationContext(String[] configLocations, ApplicationContext parent) throws BeansException { super(parent); this.configLocations = configLocations; //IoC容器的初始化過程,其初始化過程的大致步驟由AbstractApplicationContext來定義 refresh(); }
關鍵之處在於refresh方法,此方法繼承於ClassPathXmlApplicationContext的間接父類:
public abstract class AbstractApplicationContext extends DefaultResourceLoader
implements ConfigurableApplicationContext, DisposableBean {
Spring的AbstractApplicationContext是ApplicationContext抽象實現類,該抽象類的refresh()方法定義了Spring容器在加載配置文件后的各項處理過程,這些處理過程清晰刻畫了Spring容器啟動時所執行的各項操作(創建Spring容器如ClassPathXmlApplicationContext)。下面,我們來看一下refresh()內部定義了哪些執行邏輯:
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();--------(1) // 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);-------------------------------------(2) // Register bean processors that intercept bean creation registerBeanPostProcessors(beanFactory);---------------------------------------------(3) // Initialize message source for this context. initMessageSource();-------------------------------------------------------------------------(4) // Initialize event multicaster for this context. initApplicationEventMulticaster();-----------------------------------------------------------(5) // Initialize other special beans in specific context subclasses. onRefresh();------------------------------------------------------------------------------------(6) // Check for listener beans and register them. registerListeners();----------------------------------------------------------------------------(7) // Instantiate singletons this late to allow them to access the message source. beanFactory.preInstantiateSingletons();--------------------------------------------------(8) // Last step: publish corresponding event. publishEvent(new ContextRefreshedEvent(this));---------------------------------------(9) } catch (BeansException ex) { // Destroy already created singletons to avoid dangling resources. beanFactory.destroySingletons(); throw ex; } } } protected ConfigurableListableBeanFactory obtainFreshBeanFactory() { refreshBeanFactory(); ConfigurableListableBeanFactory beanFactory = getBeanFactory(); return beanFactory; } protected abstract void refreshBeanFactory() throws BeansException, IllegalStateException; public abstract ConfigurableListableBeanFactory getBeanFactory() throws IllegalStateException;
1.初始化BeanFactory:根據配置文件實例化BeanFactory,getBeanFactory()方法由具體子類實現。在這一步里,Spring將配置文件的信息解析成為一個個的BeanDefinition對象並裝入到容器的Bean定義注冊表(BeanDefinitionRegistry)中,但此時Bean還未初始化;obtainFreshBeanFactory()會調用自身的refreshBeanFactory(),而refreshBeanFactory()方法由子類AbstractRefreshableApplicationContext實現,該方法返回了一個創建的DefaultListableBeanFactory對象,這個對象就是由ApplicationContext管理的BeanFactory容器對象。
這一步的操作相當於,如果我們在自己的應用代碼中不用ApplicationContext而直接用BeanFactory時創建BeanFactory對象的操作
核心代碼如下:
public abstract class AbstractRefreshableApplicationContext extends AbstractApplicationContext { } /** 該ApplicationContext管理的BeanFactory容器對象*/ private DefaultListableBeanFactory beanFactory; protected final void refreshBeanFactory() throws BeansException { // Shut down previous bean factory, if any. ConfigurableListableBeanFactory oldBeanFactory = null; synchronized (this.beanFactoryMonitor) { oldBeanFactory = this.beanFactory; } if (oldBeanFactory != null) { oldBeanFactory.destroySingletons(); synchronized (this.beanFactoryMonitor) { this.beanFactory = null; } } // Initialize fresh bean factory. try { // 創建容器對象 DefaultListableBeanFactory beanFactory = createBeanFactory(); // Customize the internal bean factory used by this context customizeBeanFactory(beanFactory); // 裝載配置文件,並傳入相關聯的BeanFactory對象,作為BeanDefinition的容器 loadBeanDefinitions(beanFactory); synchronized (this.beanFactoryMonitor) { this.beanFactory = beanFactory; } } catch (IOException ex) { throw new ApplicationContextException( "I/O error parsing XML document for application context [" + getDisplayName() + "]", ex); } } // 創建Spring默認的容器對象 protected DefaultListableBeanFactory createBeanFactory() { return new DefaultListableBeanFactory(getInternalParentBeanFactory()); } // 該方法為一個鈎子方法,子類可以覆蓋它對當前上下文管理的BeanFactory提供客戶化操作,也可以忽略 protected void customizeBeanFactory(DefaultListableBeanFactory beanFactory) { } // 裝載配置文件的方法,需要子類實現 protected abstract void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws IOException, BeansException;
對於上面裝載配置文件的方法,由其子類擴展實現:
public abstract class AbstractXmlApplicationContext extends AbstractRefreshableApplicationContext {} protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws IOException { // 使用XMLBeanDefinitionReader來載入bean定義信息的XML文件,傳入關聯的BeanFactory XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory); // 這里配置reader的環境,其中ResourceLoader是我們用來定位bean定義信息資源位置的 // 因為上下文本身實現了ResourceLoader接口,所以可以直接把上下文作為ResourceLoader傳遞入 beanDefinitionReader.setResourceLoader(this); beanDefinitionReader.setEntityResolver(new ResourceEntityResolver(this)); // Allow a subclass to provide custom initialization of the reader, // then proceed with actually loading the bean definitions. initBeanDefinitionReader(beanDefinitionReader); // 這里轉到定義好的XmlBeanDefinitionReader中對載入bean信息進行處理 loadBeanDefinitions(beanDefinitionReader); } protected void loadBeanDefinitions(XmlBeanDefinitionReader reader) throws BeansException, IOException { Resource[] configResources = getConfigResources(); if (configResources != null) { reader.loadBeanDefinitions(configResources); } String[] configLocations = getConfigLocations(); if (configLocations != null) { reader.loadBeanDefinitions(configLocations); } } reader.loadBeanDefinitions(configLocations);涉及到XmlBeanDefinitionReader 工具類的使用(以后整理)
2.調用工廠后處理器:根據反射機制從BeanDefinitionRegistry中找出所有BeanFactoryPostProcessor類型的Bean,並調用其postProcessBeanFactory()接口方法;
經過第一步加載配置文件,已經把配置文件中定義的所有bean裝載到BeanDefinitionRegistry這個Beanfactory中,對於ApplicationContext應用來說這個BeanDefinitionRegistry類型的BeanFactory就是Spring默認的DefaultListableBeanFactory
public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFactory
implements ConfigurableListableBeanFactory, BeanDefinitionRegistry
在這些被裝載的bean中,若有類型為BeanFactoryPostProcessor的bean(配置文件中配置的),則將對應的BeanDefinition生成BeanFactoryPostProcessor對象
容器掃描BeanDefinitionRegistry中的BeanDefinition,使用java反射自動識別出Bean工廠后處理器(實現BeanFactoryPostProcessor接口)的bean,然后調用這些bean工廠后處理器對BeanDefinitionRegistry中的BeanDefinition進行加工處理,可以完成以下兩項工作(當然也可以有其他的操作,用戶自己定義):
1 對使用到占位符的<bean>元素標簽進行解析,得到最終的配置值,這意味着對一些半成品式的BeanDefinition對象進行加工處理並取得成品的BeanDefinition對象。2 對BeanDefinitionRegistry中的BeanDefinition進行掃描,通過Java反射機制找出所有屬性編輯器的Bean(實現java.beans.PropertyEditor接口的Bean),並自動將它們注冊到Spring容器的屬性編輯器注冊表中(PropertyEditorRegistry),這個Spring提供了實現:CustomEditorConfigurer,它實現了BeanFactoryPostProcessor,用它來在此注冊自定義屬性編輯器;
AbstractApplicationContext中的代碼如下:
protected void invokeBeanFactoryPostProcessors(ConfigurableListableBeanFactory beanFactory) { // Invoke factory processors registered with the context instance. for (Iterator it = getBeanFactoryPostProcessors().iterator(); it.hasNext();) { BeanFactoryPostProcessor factoryProcessor = (BeanFactoryPostProcessor) it.next(); factoryProcessor.postProcessBeanFactory(beanFactory); } // Do not initialize FactoryBeans here: We need to leave all regular beans // 通過ApplicatinContext管理的beanfactory獲取已經注冊的BeanFactoryPostProcessor類型的bean的名字 String[] factoryProcessorNames = beanFactory.getBeanNamesForType(BeanFactoryPostProcessor.class, true, false); // Separate between BeanFactoryPostProcessors that implement the Ordered // interface and those that do not. List orderedFactoryProcessors = new ArrayList(); List nonOrderedFactoryProcessorNames = new ArrayList(); for (int i = 0; i < factoryProcessorNames.length; i++) { if (isTypeMatch(factoryProcessorNames[i], Ordered.class)) { // 調用beanfactory的getBean取得所有的BeanFactoryPostProcessor對象 orderedFactoryProcessors.add(beanFactory.getBean(factoryProcessorNames[i])); } else { nonOrderedFactoryProcessorNames.add(factoryProcessorNames[i]); } } // First, invoke the BeanFactoryPostProcessors that implement Ordered. Collections.sort(orderedFactoryProcessors, new OrderComparator()); for (Iterator it = orderedFactoryProcessors.iterator(); it.hasNext();) { BeanFactoryPostProcessor factoryProcessor = (BeanFactoryPostProcessor) it.next(); // 執行BeanFactoryPostProcessor的方法,傳入當前持有的beanfactory對象,以獲取要操作的 // BeanDefinition factoryProcessor.postProcessBeanFactory(beanFactory); } // Second, invoke all other BeanFactoryPostProcessors, one by one. for (Iterator it = nonOrderedFactoryProcessorNames.iterator(); it.hasNext();) { String factoryProcessorName = (String) it.next(); ((BeanFactoryPostProcessor) getBean(factoryProcessorName)). postProcessBeanFactory(beanFactory); } }
BeanFactoryPostProcessor接口代碼如下,實際的操作由用戶擴展並配置--擴展點
參考:spring擴展點之一:BeanFactoryPostProcessor和BeanPostProcessor
3.注冊Bean后處理器:根據反射機制從BeanDefinitionRegistry中找出所有BeanPostProcessor類型的Bean,並將它們注冊到容器Bean后處理器的注冊表中;
AbstractApplicatinContext中對應代碼如下:
protected void registerBeanPostProcessors(ConfigurableListableBeanFactory beanFactory) { String[] processorNames = beanFactory.getBeanNamesForType(BeanPostProcessor.class, true, false); // Register BeanPostProcessorChecker that logs an info message when int beanProcessorTargetCount = beanFactory.getBeanPostProcessorCount() + 1 + processorNames.length; beanFactory.addBeanPostProcessor(new BeanPostProcessorChecker(beanFactory, beanProcessorTargetCount)); List orderedProcessors = new ArrayList(); List nonOrderedProcessorNames = new ArrayList(); for (int i = 0; i < processorNames.length; i++) { if (isTypeMatch(processorNames[i], Ordered.class)) { orderedProcessors.add(getBean(processorNames[i])); } else { nonOrderedProcessorNames.add(processorNames[i]); } } // First, register the BeanPostProcessors that implement Ordered. Collections.sort(orderedProcessors, new OrderComparator()); for (Iterator it = orderedProcessors.iterator(); it.hasNext();) { // 注冊bean后處理器,該方法定義於ConfigurableBeanFactory接口 beanFactory.addBeanPostProcessor((BeanPostProcessor) it.next()); } // Second, register all other BeanPostProcessors, one by one. for (Iterator it = nonOrderedProcessorNames.iterator(); it.hasNext();) { String processorName = (String) it.next(); beanFactory.addBeanPostProcessor((BeanPostProcessor) getBean(processorName)); } }
整段代碼類似於第三步的調用工廠后處理器,區別之處在於,工廠后處理器在獲取后立即調用,而Bean后處理器在獲取后注冊到上下文持有的beanfactory中,供以后操作調用(在用戶獲取bean的過程中,對已經完成屬性設置工作的Bean進行后續加工,他加工的是bean,而工廠后處理器加工的是BeanDefinition)
BeanPostProcessor 接口代碼如下,實際的操作由用戶擴展並配置--擴展點
參考:spring擴展點之一:BeanFactoryPostProcessor和BeanPostProcessor
4.初始化消息源:初始化容器的國際化信息資源;
源代碼如下:
protected void initMessageSource() {
// 補充
}
5.初始化應用上下文事件廣播器;(觀察者模式中的具體主題角色,持有觀察者角色的集合,稱為注冊表)
AbstractApplciationContext擁有一個applicationEventMulticaster 成員變量,applicationEventMulticaster 提供了容器監聽器的注冊表,成其為事件廣播器。在第七步中將會將事件監聽器裝入其中
AbstractApplicationContext中的代碼如下:
private ApplicationEventMulticaster applicationEventMulticaster; protected void initApplicationEventMulticaster() { // "applicationEventMulticaster",先看配置文件中有無配置該類型類(用戶擴展 擴展點,如何擴展) if (containsLocalBean(APPLICATION_EVENT_MULTICASTER_BEAN_NAME)) { this.applicationEventMulticaster = (ApplicationEventMulticaster) getBean(APPLICATION_EVENT_MULTICASTER_BEAN_NAME, ApplicationEventMulticaster.class); } else { // 若沒有,則應用Spring框架提供的事件廣播器實例 this.applicationEventMulticaster = new SimpleApplicationEventMulticaster(); } } public boolean containsLocalBean(String name) { return getBeanFactory().containsLocalBean(name); } public Object getBean(String name, Class requiredType) throws BeansException { return getBeanFactory().getBean(name, requiredType); }
Spring初始化事件廣播器,用戶可以在配置文件中為容器定義一個自定義的事件廣播器(bean的名稱要為"applicationEventMulticaster"),只要實現ApplicationEventMulticaster就可以了,Spring在此會根據beanfactory自動獲取。如果沒有找到外部配置的事件廣播器,Spring使用SimpleApplicationEventMulticaster作為事件廣播器。
6.初始化其他特殊的Bean:這是一個鈎子方法,子類可以借助這個鈎子方法執行一些特殊的操作:如AbstractRefreshableWebApplicationContext就使用該鈎子方法執行初始化ThemeSource的操作;
protected void onRefresh() throws BeansException {//--擴展點 package org.springframework.context; // For subclasses: do nothing by default. }
7.注冊事件監聽器;(觀察者模式中的觀察者角色)
Spring根據上下文持有的beanfactory對象,從它的BeanDefinitionRegistry中找出所有實現org.springfamework.context.ApplicationListener的bean,將BeanDefinition對象生成bean,注冊為容器的事件監聽器,實際的操作就是將其添加到事件廣播器所提供的監聽器注冊表中
AbstractApplicationContext中的代碼如下:
/** Statically specified listeners */ private List applicationListeners = new ArrayList(); public List getApplicationListeners() { return this.applicationListeners; } protected void registerListeners() { // Register statically specified listeners first. for (Iterator it = getApplicationListeners().iterator(); it.hasNext();) { addListener((ApplicationListener) it.next()); } // 獲取ApplicationListener類型的所有bean,即事件監聽器 // uninitialized to let post-processors apply to them! Collection listenerBeans = getBeansOfType(ApplicationListener.class, true, false).values(); for (Iterator it = listenerBeans.iterator(); it.hasNext();) { // 將事件監聽器裝入第五步初始化的事件廣播器 addListener((ApplicationListener) it.next()); } } public Map getBeansOfType(Class type, boolean includePrototypes, boolean allowEagerInit) throws BeansException { return getBeanFactory().getBeansOfType(type, includePrototypes, allowEagerInit); } protected void addListener(ApplicationListener listener) {
getApplicationEventMulticaster().addApplicationListener(listener); }
ApplicationListener 的源代碼如下:
package org.springframework.context; import java.util.EventListener; /** * Interface to be implemented by application event listeners. * @see org.springframework.context.event.ApplicationEventMulticaster */ public interface ApplicationListener extends EventListener { void onApplicationEvent(ApplicationEvent event); }
--擴展點 參考:spring擴展點之三:Spring 的監聽事件 ApplicationListener 和 ApplicationEvent 用法,在spring啟動后做些事情
8.初始化singleton的Bean:實例化所有singleton的Bean,並將它們放入Spring容器的緩存中;這就是和直接在應用中使用BeanFactory的區別之處,在創建ApplicationContext對象時,不僅創建了一個BeanFactory對象,並且還應用它實例化所有單實例的bean。
AbstractApplicationContext中的代碼如下:
beanFactory.preInstantiateSingletons();
關於BeanFactory體系的代碼參照。。。。。。
9.發布上下文刷新事件:在此處時容器已經啟動完成,發布容器refresh事件(ContextRefreshedEvent)
創建上下文刷新事件,事件廣播器負責將些事件廣播到每個注冊的事件監聽器中。
publishEvent(new ContextRefreshedEvent(this)); public void publishEvent(ApplicationEvent event) { Assert.notNull(event, "Event must not be null"); // 在此獲取事件廣播器,並調用其方法發布事件:調用所有注冊的監聽器的方法 getApplicationEventMulticaster().multicastEvent(event); if (this.parent != null) { this.parent.publishEvent(event); } }
至此,ApplicationContext對象就完成了初始化工作:創建BeanFactory來裝配BeanDefiniton,加工處理BeanDefiniton,注冊了bean后處理器,初始化了消息資源,初始化了應用上下文事件廣播器,注冊了事件監聽器,初始化了所有singleton的bean,最后發布上下文刷新事件