Spring原始碼淺析 -- XML配置檔案的載入與解析
最近在看Spring原始碼,對配置檔案資訊的載入是使用Spring的第一步 ,而這第一步就是一個非常複雜的過程....
Spring通過定義BeanDefination來管理Ioc中的各種物件以及它們之間的依賴關係,所以載入的過程其實就是將XML檔案讀取並解析成BeanDefination資料的過程。
我們以最常使用的ClassPathXmlApplicationContext為切入點
1. 建立一個ClassPathXmlApplicationContext物件,傳入檔案路徑
-
ClassPathXmlApplicationContext re = new
這個構造方法會過載到
Java程式碼- public ClassPathXmlApplicationContext(String[] configLocations, boolean refresh, ApplicationContext parent)
- throws BeansException {
- super(parent);
-
setConfigLocations(configLocations);
- if (refresh) {
- refresh();
- }
- }
其中首先設定配置路徑 setConfigLocations(configLocations) ,而後進行重新整理 refresh(), 而這個refresh()方法是Ioc容器初始化的入口
2.refresh方法的結構
refresh方法由AbstractApplicationContext實現
Java程式碼-
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) {
- // Destroy already created singletons to avoid dangling resources.
- destroyBeans();
- // Reset 'active' flag.
- cancelRefresh(ex);
- // Propagate exception to caller.
- throw ex;
- }
- }
- }
這個方法中描述了ApplicationContext的整個初始化過程,包括BeanFactory的更新,還有messagesource以及一些生命週期有關屬性的註冊,而我們關心的是BeanFactory的更新,即obtainFreshBeanFactory()方法
3.啟動對BeanDefination的載入
還是在ApplicationContext類中
Java程式碼- protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {
- refreshBeanFactory();
- ConfigurableListableBeanFactory beanFactory = getBeanFactory();
- if (logger.isDebugEnabled()) {
- logger.debug("Bean factory for " + getDisplayName() + ": " + beanFactory);
- }
- return beanFactory;
- }
它的第一步交給一個抽象方法refreshBeanFactory(), 具體的實現在AbstractRefreshableApplicationContext類中
Java程式碼- @Override
- protected final void refreshBeanFactory() throws BeansException {
- if (hasBeanFactory()) {
- destroyBeans();
- closeBeanFactory();
- }
- try {
- DefaultListableBeanFactory beanFactory = createBeanFactory();
- beanFactory.setSerializationId(getId());
- customizeBeanFactory(beanFactory);
- loadBeanDefinitions(beanFactory);
- synchronized (this.beanFactoryMonitor) {
- this.beanFactory = beanFactory;
- }
- }
- catch (IOException ex) {
- throw new ApplicationContextException("I/O error parsing bean definition source for " + getDisplayName(), ex);
- }
- }
第一步是判斷是否已經建立過BeanFactory,如果是,將它銷燬,重新建立
第二步就是建立各種ApplicationContext持有的真正容器實現類DefaultListableBeanFactory,建立Ioc容器
最後啟動BeanDefination的載入 loadBeanDefinitions(beanFactory)方法
4.BeanFactory將載入工作交給BeanDefinationReader
loadBeanDefinitions(beanFactory)方法是抽象的,又因為我們的配置檔案是XML格式的,所以具體實現實在AbstractXmlApplicationConext中
Java程式碼- @Override
- protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws BeansException, IOException {
- // Create a new XmlBeanDefinitionReader for the given BeanFactory.
- XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory);
- // Configure the bean definition reader with this context's
- // resource loading environment.
- 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);
- loadBeanDefinitions(beanDefinitionReader);
- }
這裡建立了一個XmlBeanDefinitionReader 物件,它專門用來讀取基於XML檔案格式的BeanDefinition配置,接下來過載到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);
- }
- }
首先載入Resource物件用來定位資源,Resource物件的生成在ClassPathXmlApplicationContext 中setConfigLocations(configLocations)方法實現
然後呼叫XmlBeanDefinitionReader基類AbstractBeanDefinitionReader的loadBeanDefinitions方法
Java程式碼- public int loadBeanDefinitions(Resource[] resources) throws BeanDefinitionStoreException {
- Assert.notNull(resources, "Resource array must not be null");
- int counter = 0;
- for (Resource resource : resources) {
- counter += loadBeanDefinitions(resource);
- }
- return counter;
- }
然後呼叫loadBeanDefinitions(resource)方法,此方法的具體實現在XmlBeanDefinitionReader 中
Java程式碼- public int loadBeanDefinitions(Resource resource) throws BeanDefinitionStoreException {
- return loadBeanDefinitions(new EncodedResource(resource));
- }
過載到
Java程式碼- public int loadBeanDefinitions(EncodedResource encodedResource) throws BeanDefinitionStoreException {
- Assert.notNull(encodedResource, "EncodedResource must not be null");
- if (logger.isInfoEnabled()) {
- logger.info("Loading XML bean definitions from " + encodedResource.getResource());
- }
- Set<EncodedResource> currentResources = this.resourcesCurrentlyBeingLoaded.get();
- if (currentResources == null) {
- currentResources = new HashSet<EncodedResource>(4);
- this.resourcesCurrentlyBeingLoaded.set(currentResources);
- }
- if (!currentResources.add(encodedResource)) {
- throw new BeanDefinitionStoreException(
- "Detected recursive loading of " + encodedResource + " - check your import definitions!");
- }
- try {
- InputStream inputStream = encodedResource.getResource().getInputStream();
- try {
- InputSource inputSource = new InputSource(inputStream);
- if (encodedResource.getEncoding() != null) {
- inputSource.setEncoding(encodedResource.getEncoding());
- }
- return doLoadBeanDefinitions(inputSource, encodedResource.getResource());
- }
- finally {
- inputStream.close();
-
相關推薦
Spring原始碼淺析 -- XML配置檔案的載入與解析
最近在看Spring原始碼,對配置檔案資訊的載入是使用Spring的第一步 ,而這第一步就是一個非常複雜的過程.... Spring通過定義BeanDefination來管理Ioc中的各種物件以及它們之間的依賴關係,所以載入的過程其實就是將XML檔案讀取並解析成B
XmlBeanDefinitionReader-----Spring原始碼解析 配置檔案裝載與解析
以下內容有部分摘自網路 步驟A. 讀取 Resource 檔案形成 Document 模型 類圖: XmlBeanFactory -> XmlBeanDefinitionReader Spring 使用 XmlBeanDefinitionReade
Spring MVC web.xml配置檔案
<!DOCTYPE web-app PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN" "http://java.sun.com/dtd/web-app_2_3.dtd" > <web-a
Spring的applicationContext.xml配置檔案如何查詢
目錄 一、文章前言 Spring需要載入配置檔案applicationContext.xml,那麼自帶的jar包又沒有,該如何查詢;在網上找又怕找的不對,那麼其實很簡單,當我們在jar包找不
使用Redis儲存Spring session(基於XML配置檔案)
Spring session是一種分散式session共享方案,提供了管理使用者session資訊的介面及實現。下文描述如何通過XML配置檔案的方式實現使用Redis儲存Spring session。 前置條件:Redis server已安裝就緒。 (1) pom.xml配
spring xml配置檔案bean的解析定義
spring為解析xml建立bean提供了一種非常解藕的方式。 整體架構面向介面程式設計,AbstractApplicationContext的refresh方法被呼叫時,在重新整理BeanFactory的時候會解析配置檔案。框架提供了: 介面 org.springframework.beans.fact
properties和xml配置檔案載入效率
本人通過用java.util.Properties類分別載入一個xml配置檔案和一個properties配置檔案,得到的結果大概是properties配置檔案載入的速度比xml快50倍左右(這個數字不是很精確,但可以確定的是應該有兩個數量級)!這是一個驚人的速度,所以配置檔
Spring中applicationContext.xml配置檔案中資料庫資料來源配置
<!-- 標頭檔案,主要注意一下編碼 --> <?xmlversion="1.0"encoding="UTF-8"?> <!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN""http://www.springframework
Spring mvc通過xml配置檔案方式實現簡單HelloWorld
實現Spring MVC有兩種不同的方式:基於XML配置檔案和基於註解。 這裡,我們使用XML檔案的方式來實現。 首先,我們需要在Eclipse或者是MyEclipse中新建一個web專案,並將Spr
spring boot匯入xml配置檔案
【來也匆匆,去也匆匆,在此留下您的腳印吧,轉發點贊評論; 您的認可是我最大的動力,感謝您的支援】 SpringBoot理念就是零配置程式設計,但是如果絕對需要使用XML的配置,我們建議您仍舊從一個@Configuration類開始,你可以使用@ImportResouce註解
三、Spring Boot專案中MyBatis配置檔案載入深入解析
開發十年,就只剩下這套架構體系了! >>>
Tomcat7.0原始碼分析——server.xml檔案的載入與解析
前言作為Java程式設計師,對於Tomcat的server.xml想必都不陌生。本文基於Tomcat7.0的Java原始碼,對server.xml檔案是如何載入和解析進行分析。載入過程分析Bootstrap的load方法用於載入Tomcat的server.xml,實際是通過反
Spring原始碼解析和配置檔案載入
Spring類的繼承結構圖: Spring運用了大量的模板方法模式和策略模式,所以各位看原始碼的時候,務必留意,每一個繼承的層次都有不同的作用,然後將相同的地方抽取出來,依賴抽象將不同的處理按照不同的策略去處理。 步驟A. 讀取 Resource 檔案形成 Documen
不認識spring xml配置檔案dtd和xsd型別,血與淚的教訓啊
今天在初次使用spring原始碼的時候,在spring4.2中使用了xsd型別的配置檔案,導致一直解析配置檔案出錯: 找不到元素 'beans' 的宣告 後來從原始碼工程的test/sources目錄中copy新的dtd格式,該巴改巴就成功了。真是汗啊(⊙﹏⊙)b 記住了,
Spring原始碼分析3 — spring XML配置檔案的解析流程
1 介紹 建立並初始化spring容器中,關鍵一步就是讀取並解析spring XML配置檔案。這個過程比較複雜,本文將詳細分析整個流程。先看涉及到的關鍵類。 XmlWebApplicationContext:web應用的預設Spring容器 XmlBean
Spring中載入xml配置檔案的常用的幾種方式
專案中一個需求就是所有的功能都是外掛的形式裝入系統,這就需要利用Spring去動態載入某一位置下的配置檔案,就總結了下Spring中載入xml配置檔案的方式, xml是最常見的spring 應用系統配置源。Spring中的幾種容器都支援使用xml裝配bean,包括: X
Spring 載入xml配置檔案的方式 ApplicationContext
大家都知道Java讀普通檔案是通過Basic I/O 中的InputStream、OutStream、Reader、Writer 等實現的。在spring 框架中,它是怎樣識別xml這個配置檔案的呢? 這就要靠IoC容器的兩個介面BeanFactory 和Ap
讓Eclipse中spring的xml配置檔案出現屬性和類提示
在spring配置檔案中可以讓配置bean的時候出現提示,這裡需要做一些設定。設定包括安裝springide外掛,spring-beans-version.xsd檔案引入,增加xml編輯提示的字元,預設只有=>:。最後是讓配置檔案可以通過Spring Config Editor的方式開
轉:ssm spring+springmvc+mybatis中的xml配置檔案詳解
這幾天一直在整合SSM框架,雖然網上有很多已經整合好的,但是對於裡面的配置檔案並沒有進行過多的說明,很多人知其然不知其所以然,經過幾天的搜尋和整理,今天總算對其中的XML配置檔案有了一定的瞭解,所以拿出來一起分享一下,希望有不足的地方大家批評指正~~~ 首先 這篇文章暫時只對框架中所要用到的配
Maven之pom.xml與setting.xml配置檔案詳解
一.pom.xml詳解 1.概述 pom中節點如下分佈 <project xmlns="http://maven.apache.org/