上兩篇,我們已經基本的分析完了XmlBeanFactory的應用實例,本章我們一起來分析一下ApplicationContext。大佬略過
前兩兩篇已經將基本的XmlBeanFactory操作實例講完了,這裏我們來聊聊ApplicationContext。在之前也提過,這兩個東西基本流程上應該是相差不多的。比如我們之前推測:
- 讀取配置文件
- 根據配置文件找到對應的類並通過反射來實例化
- 然後存入容器,被調用的時候取出
ApplicationContext和XmlBeanFactory的區別
在ApplicationContext的源碼解析中,這些推測還能使用嗎?答案是可以的。之前我們聊過IOC容器的設計與實現,無非就是兩個系列,一個BeanFactory,一個ApplicationContext。那麼我們之前看的XmlBeanFactory屬於哪一種類呢?先來看一下XmlBeanFactory的類圖
XmlBeanFactory繼承體系是
XmlBeanFactory -> DefaultListableBeanFactory -> AbstractAutowireCapableBeanFactory -> AbstractBeanFactory -> FactoryBeanRegistrySupport -> DefaultSingletonBeanRegistry -> SimpleAliasRegistry -> AliasRegistry
但是請注意:XmlBeanFactory是在DefaultListableBeanFactory的基礎上做擴展的。其實最終還是實現了BeanFactory接口。而我們的ApplicationContext,它是做爲一種容器的高級形態存在。應用上下文,在簡單的容器上增加了許多其他的特性。爲什麼這麼說呢?我們來看看ApplicationContext的類圖。
不難發現ApplicationContext其實也是實現了BeanFactory,但是這裏可以明顯的看到,ApplicationContext做了更多的支持。
BeanFactory
BeanFactory是Spring最核心的所在,很多面試題問Spring是什麼?其實就可以直接回答:Spring其實就是一個BeanFactory的巨大封裝,當然好像有點片面,BeanFactory確確實實是Spring最核心的內容。
BeanFactory提供的是最基本的IOC容器的功能,關於這些功能,我們可以來讀一下他的源碼
String FACTORY_BEAN_PREFIX = "&";
/**
* 根據名稱獲取bean
*/
Object getBean(String name) throws BeansException;
<T> T getBean(String name, Class<T> requiredType) throws BeansException;
<T> T getBean(Class<T> requiredType) throws BeansException;
Object getBean(String name, Object... args) throws BeansException;
/**
* 是否包含bean
*/
boolean containsBean(String name);
/**
* 查詢bean是否是Singleton類型
*/
boolean isSingleton(String name) throws NoSuchBeanDefinitionException;
/**
* 查詢bean是否是Prototype類型
*/
boolean isPrototype(String name) throws NoSuchBeanDefinitionException;
/**
* 查詢bean的class類型是否是特定的class類型
*/
boolean isTypeMatch(String name, Class<?> targetType)
throws NoSuchBeanDefinitionException;
/**
* 查詢bean的class類型
*/
Class<?> getType(String name) throws NoSuchBeanDefinitionException;
/**
* 查詢bean的所有別名
*/
String[] getAliases(String name);
其實它的代碼並不多,但是它提供了使用IOC容器的規範。理解這些呢,有助於我們理解ApplicationContext,我們可以直接認爲BeanFactory是一種簡單的容器形式,而ApplicationContext它是一種高級的容器形式。
到這裏,其實我們已經看到XmlBeanFactory和ApplicationContext的一些區別了。但是這裏其實不是那麼的明顯。我們不妨再來看看那ApplicationContext它的實現類ClassPathXmlApplicationContext,也就是我們代碼裏面用的。它的一個源碼和XmlBeanFactory的區別在哪
ClassPathXmlApplicationContext
public ClassPathXmlApplicationContext(String[] configLocations, boolean refresh, @Nullable ApplicationContext parent) throws BeansException {
super(parent);
this.setConfigLocations(configLocations);
if (refresh) {
this.refresh();
}
}
它的初始化在不斷的調用super(parent),但是refresh()方法完成了容器的初始化。
refresh()方法的實現代碼如下
public void refresh() throws BeansException, IllegalStateException {
synchronized(this.startupShutdownMonitor) {
this.prepareRefresh(); // 準備工作
ConfigurableListableBeanFactory beanFactory = this.obtainFreshBeanFactory(); // 獲取ConfigurableListableBeanFactory最終的目的是DefaultListableBeanFactory
this.prepareBeanFactory(beanFactory); // 準備bean工廠
try {
this.postProcessBeanFactory(beanFactory); // 一個空的實現,注意這裏的spring版本號爲:5.3x
this.invokeBeanFactoryPostProcessors(beanFactory); // 註冊bean的工廠
this.registerBeanPostProcessors(beanFactory);
this.initMessageSource(); // Spring 從所有的 @Bean 定義中抽取出來了 BeanPostProcessor,然後都註冊進 beanPostProcessors,等待後面的的順序調用 註冊BeanPostProcessor
this.initApplicationEventMulticaster(); // 初始化事件監聽多路廣播器
this.onRefresh(); // 一個空的實現
this.registerListeners(); // 註冊監聽器
this.finishBeanFactoryInitialization(beanFactory); // 到了spring加載流程最複雜的一步,開始實例化所有的bd
this.finishRefresh();// 刷新完成工作
} catch (BeansException var9) {
if (this.logger.isWarnEnabled()) {
this.logger.warn("Exception encountered during context initialization - cancelling refresh attempt: " + var9);
}
this.destroyBeans();
this.cancelRefresh(var9);
throw var9;
} finally {
this.resetCommonCaches();
}
}
}
方法從總體上看 還算比較清晰 用幾個大的方法高度概括了refresh()做了些什麼。後面我們會詳細來解讀這些流程,這裏僅做一個總結。
到這裏位置,我們看到了ClassPathXmlApplicationContext的一個流程,和我們的XmlBeanFactory的區別相當的大,在我們之前的推測中,他應該先去加載xml,其實這裏也做了,只是隱藏的比較深,在這個加載流程的第二部的具體內容裏面,我們這裏貼一下核心代碼
ConfigurableListableBeanFactory beanFactory = this.obtainFreshBeanFactory();
this.refreshBeanFactory();
this.loadBeanDefinitions(beanFactory);
protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws BeansException, IOException {
XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory);
beanDefinitionReader.setEnvironment(this.getEnvironment());
beanDefinitionReader.setResourceLoader(this);
beanDefinitionReader.setEntityResolver(new ResourceEntityResolver(this));
this.initBeanDefinitionReader(beanDefinitionReader);
this.loadBeanDefinitions(beanDefinitionReader);
}
其實bean的初始化和容器的初始化也在這個流程裏面全部提現了,這個我們後面再講,但是從我們總結的內容來看,其實和我們的推測是大差不差的,只是多了很多其他的東西而已。多出來的這些東西也正是我們兩種容器實現的區別所在。
總結:
- BeanFactory的基本實現提供了基本的IOC容器,ApplicaitonContext以高級形態出現,增加了很多附加功能。
- XmlBeanFactory是我們BeanFactory一種最基本應用
- XmlBeanFactory和ClassPathXmlApplicationContext都具備我們推測的流程,但是實現有所不同,而且具體流程上,兩個區別很大