欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

spring的applicationContext.xml文件與NamespaceHandler解析

 更新時間:2023年12月02日 09:52:32   作者:服務端開發(fā)  
這篇文章主要介紹了spring的applicationContext.xml文件與NamespaceHandler解析,Spring容器啟動,在創(chuàng)建BeanFactory時,需要加載和解析當前ApplicationContext對應的配置文件applicationContext.xml,從而獲取bean相關的配置信息,需要的朋友可以參考下

applicationContext.xml文件解析

  • Spring容器啟動,在創(chuàng)建BeanFactory時,需要加載和解析當前ApplicationContext對應的配置文件applicationContext.xml,從而獲取bean相關的配置信息。
  • 在內部實現(xiàn)的調用關系為:ApplicationContext通過XmlBeanDefinitionReader來完成從applicationContext.xml獲取應用配置的bean信息,并注冊到關聯(lián)的BeanFactory中。XmlBeanDefinitionReader的主要工作為解析xml文件的標簽,包括從bean標簽直接創(chuàng)建BeanDefinition,以及創(chuàng)建用于處理context:component-scan標簽的BeanFactoryPostProcessor,然后間接創(chuàng)建BeanDefinitions。
  • 整個解析過程如下:
    • XmlBeanDefinitionReader創(chuàng)建DefaultBeanDefinitionDocumentReader對象實例,讀取XML文件并封裝成Document對象,然后將該Document對象作為參數(shù),調用DefaultBeanDefinitionDocumentReader的registerBeanDefinitions,在registerBeanDefinitions中解析XML文件的內容,從中獲取并生成beanDefinitions;
    • registerBeanDefinitions方法:從XML文件對應的Document對象獲取root Element,從root Element一直往下解析所有的xml標簽Element;
    • 針對每個xml標簽Element,解析過程為:新增一個與該Element對應的BeanDefinitionParserDelegate,根據(jù)該Element的命名空間nameSpaceUri,從NamespaceHandlerResolver獲取該nameSpaceUri對應的NamespaceHandler;
    • 其中NamespaceHandler內部維護了xml標簽和xml標簽解析器BeanDefinitionParser的映射,所以由NamespaceHandler獲取當前正在處理的xml標簽Element對應的標簽處理器BeanDefinitionParser(如< bean …>標簽處理器則直接創(chuàng)建BeanDefinition對象,而< component-scan …>標簽則是創(chuàng)建一個BeanFactoryPostProcessor,之后由該BeanFactory后置處理器通過掃描指定包獲取類并生成BeanDefinition注冊到BeanFactory),由該BeanDefinitionParser從xml標簽Element生成注冊到BeanFactory的BeanDefinition,或者生成BeanFactoryPostProcessor。
    • 所以這里就需要定義每個標簽對應一個特定的標簽解析器了,在spring內部是通過BeanDefinitionParser接口來定義的。

NamespaceHandler

  • 在Spring的設計當中,通常每個標簽都屬于一個特定的名稱空間來避免名稱沖突,如context名稱空間,mvc名稱空間等,每個名稱空間內部可定義多個標簽。
  • 使用NamespaceHandler接口來維護每個名稱空間內部的標簽 和標簽處理器之間的映射關系。這樣XmlBeanDefinitionReader在解析applicationContext.xml文件時,遇到某個名稱空間,則獲取這名稱空間對應的NamespaceHandler,然后通過NamespaceHandler進一步獲取內部標簽對應的標簽處理器。

Spring內部的使用和源碼實現(xiàn)

  • 在spring-context,spring-webmvc,spring-beans等spring框架子項目的META-INF/spring.handlers文件中,定義標簽命名空間與NamespaceHandler實現(xiàn)類之間的映射關系。
  • 如下為spring-webmvc子項目的META-INF/spring.handlers文件內容:
http\://www.springframework.org/schema/mvc=org.springframework.web.servlet.config.MvcNamespaceHandler

對應的NamespaceHandler的實現(xiàn)類為:

package org.springframework.web.servlet.config;
/**
 * {@link NamespaceHandler} for Spring MVC configuration namespace.
 *
 * @author Keith Donald
 * @author Jeremy Grelle
 * @author Sebastien Deleuze
 * @since 3.0
 */
public class MvcNamespaceHandler extends NamespaceHandlerSupport {
	@Override
	public void init() {
		registerBeanDefinitionParser("annotation-driven", new AnnotationDrivenBeanDefinitionParser());
		registerBeanDefinitionParser("default-servlet-handler", new DefaultServletHandlerBeanDefinitionParser());
		registerBeanDefinitionParser("interceptors", new InterceptorsBeanDefinitionParser());
		registerBeanDefinitionParser("resources", new ResourcesBeanDefinitionParser());
		registerBeanDefinitionParser("view-controller", new ViewControllerBeanDefinitionParser());
		registerBeanDefinitionParser("redirect-view-controller", new ViewControllerBeanDefinitionParser());
		registerBeanDefinitionParser("status-controller", new ViewControllerBeanDefinitionParser());
		registerBeanDefinitionParser("view-resolvers", new ViewResolversBeanDefinitionParser());
		registerBeanDefinitionParser("tiles-configurer", new TilesConfigurerBeanDefinitionParser());
		registerBeanDefinitionParser("freemarker-configurer", new FreeMarkerConfigurerBeanDefinitionParser());
		registerBeanDefinitionParser("groovy-configurer", new GroovyMarkupConfigurerBeanDefinitionParser());
		registerBeanDefinitionParser("script-template-configurer", new ScriptTemplateConfigurerBeanDefinitionParser());
		registerBeanDefinitionParser("cors", new CorsBeanDefinitionParser());
	}
}
  • XmlBeanDefinitionReader主要是從applicationContext.xml創(chuàng)建一個Document對象,交給子組件BeanDefinitionDocumentReader處理這個Document對象。而NamespaceHandler的實現(xiàn)類主要是在BeanDefinitionDocumentReader中在解析Document對象的Element元素時調用,如下:
public BeanDefinition parseCustomElement(Element ele, @Nullable BeanDefinition containingBd) {
	String namespaceUri = getNamespaceURI(ele);
	if (namespaceUri == null) {
		return null;
	}
	// 獲取一個NamespaceHandler
	NamespaceHandler handler = this.readerContext.getNamespaceHandlerResolver().resolve(namespaceUri);
	if (handler == null) {
		error("Unable to locate Spring NamespaceHandler for XML schema namespace [" + namespaceUri + "]", ele);
		return null;
	}
	// 通過這個NamespaceHandler
	// 在它里面維護的parser集合中找到
	// 與該標簽對應的parser,由該parser來執(zhí)行解析
	return handler.parse(ele, new ParserContext(this.readerContext, this, containingBd));
}
  • 以上已經(jīng)說明了通過XmlBeanDefinitionReader的NamespaceHandlerResolver維護:名稱空間和NamespaceHandler的映射;通過NamespaceHandler來維護標簽和Parser的映射,那么兩者是什么時候初始化注冊的呢?
  • 其實NamespaceHandler和Parser的初始化,使用的是懶加載機制,即當調用了NamespaceHandlerResolver的resolve方法時,才進行加載,加載之后進行緩存。如下:

NamespaceHandler的初始化:在DefaultNamespaceHandlerResolver的getHandlerMappings方法實現(xiàn)。

在resolve方法中調用getHandlerMappings方法。

/**
 * Load the specified NamespaceHandler mappings lazily.
 */
private Map<String, Object> getHandlerMappings() {
	Map<String, Object> handlerMappings = this.handlerMappings;
	if (handlerMappings == null) {
		synchronized (this) {
			handlerMappings = this.handlerMappings;
			if (handlerMappings == null) {
				if (logger.isTraceEnabled()) {
					logger.trace("Loading NamespaceHandler mappings from [" + this.handlerMappingsLocation + "]");
				}
				try {
					Properties mappings =
							PropertiesLoaderUtils.loadAllProperties(this.handlerMappingsLocation, this.classLoader);
					if (logger.isTraceEnabled()) {
						logger.trace("Loaded NamespaceHandler mappings: " + mappings);
					}
					handlerMappings = new ConcurrentHashMap<>(mappings.size());
					CollectionUtils.mergePropertiesIntoMap(mappings, handlerMappings);
					this.handlerMappings = handlerMappings;
				}
				catch (IOException ex) {
					throw new IllegalStateException(
							"Unable to load NamespaceHandler mappings from location [" + this.handlerMappingsLocation + "]", ex);
				}
			}
		}
	}
	return handlerMappings;
}
  1. 從META-INF/spring.handlers文件加載鍵值對,并緩存在類型為ConcurrentHashMap的handlerMappings中;
  2. 注意這里并沒有初始化NamespaceHandler,即handlerMappings的value還是String類型。

NamespaceHandler包含的parsers的初始化:在resolve方法中進行懶加載初始化。

  /**
   * Locate the {@link NamespaceHandler} for the supplied namespace URI
   * from the configured mappings.
   * @param namespaceUri the relevant namespace URI
   * @return the located {@link NamespaceHandler}, or {@code null} if none found
   */
  @Override
  @Nullable
  public NamespaceHandler resolve(String namespaceUri) {
      // 懶加載NamespaceHandler的handlerMappings
  	Map<String, Object> handlerMappings = getHandlerMappings();
  	Object handlerOrClassName = handlerMappings.get(namespaceUri);
  	if (handlerOrClassName == null) {
  		return null;
  	}
  	// 不是第一次調用,則已經(jīng)是NamespaceHandler類型了,可以直接返回
  	else if (handlerOrClassName instanceof NamespaceHandler) {
  		return (NamespaceHandler) handlerOrClassName;
  	}
  	// 第一次調用,由上面分析可知:
  	// 剛開始從META-INF/spring.handlers
  	// 讀出時,handlerMappings的value是字符串
  	else {
  		String className = (String) handlerOrClassName;
  		try {
  		// 加載NamespaceHandler
  			Class<?> handlerClass = ClassUtils.forName(className, this.classLoader);
  			if (!NamespaceHandler.class.isAssignableFrom(handlerClass)) {
  				throw new FatalBeanException("Class [" + className + "] for namespace [" + namespaceUri +
  						"] does not implement the [" + NamespaceHandler.class.getName() + "] interface");
  			}
  			NamespaceHandler namespaceHandler = (NamespaceHandler) BeanUtils.instantiateClass(handlerClass);
  			// 調用init方法完成parsers的初始化
  			namespaceHandler.init();
  			handlerMappings.put(namespaceUri, namespaceHandler);
  			return namespaceHandler;
  		}
  		catch (ClassNotFoundException ex) {
  			throw new FatalBeanException("Could not find NamespaceHandler class [" + className +
  					"] for namespace [" + namespaceUri + "]", ex);
  		}
  		catch (LinkageError err) {
  			throw new FatalBeanException("Unresolvable class definition for NamespaceHandler class [" +
  					className + "] for namespace [" + namespaceUri + "]", err);
  		}
  	}
  }
  protected final void registerBeanDefinitionParser(String elementName, BeanDefinitionParser parser) {
    this.parsers.put(elementName, parser);
  }

NamespaceHandler的init方法實現(xiàn):各個NamespaceHandler接口實現(xiàn)類,在init方法中注冊xml的標簽和Parser之間的映射關系:如下為context標簽的名稱空間處理器ContextNamespaceHandler:

/**
 * {@link org.springframework.beans.factory.xml.NamespaceHandler}
 * for the '{@code context}' namespace.
 *
 * @author Mark Fisher
 * @author Juergen Hoeller
 * @since 2.5
 */
public class ContextNamespaceHandler extends NamespaceHandlerSupport {
	@Override
	public void init() {
		registerBeanDefinitionParser("property-placeholder", new PropertyPlaceholderBeanDefinitionParser());
		registerBeanDefinitionParser("property-override", new PropertyOverrideBeanDefinitionParser());
		registerBeanDefinitionParser("annotation-config", new AnnotationConfigBeanDefinitionParser());
		// <context:component-scan />
    	registerBeanDefinitionParser("component-scan", new ComponentScanBeanDefinitionParser());
		registerBeanDefinitionParser("load-time-weaver", new LoadTimeWeaverBeanDefinitionParser());
		registerBeanDefinitionParser("spring-configured", new SpringConfiguredBeanDefinitionParser());
		registerBeanDefinitionParser("mbean-export", new MBeanExportBeanDefinitionParser());
		registerBeanDefinitionParser("mbean-server", new MBeanServerBeanDefinitionParser());
	}
}

插件機制拓展支持

如果需要開發(fā)一個插件并自定義標簽,然后融入到Spring容器中,則可以在自身插件項目中,基于NamespaceHandler來實現(xiàn),如在Dubbo項目中,就是利用了Spring的這個機制來容器到Spring框架的

基本步驟包括:

  1. 自定義xsd標簽定義,并添加到插件項目的META-INF目錄中,路徑類似于一個普通pacakage下面的一個類;
  2. 實現(xiàn)BeanDefinitionParser接口,定義標簽的處理邏輯;
  3. 實現(xiàn)NamespaceHandler接口,一般繼承Spring的NamespaceHandlerSupport即可。在init方法中,使用registerBeanDefinitionParser方法配置標簽名稱和BeanDefinitionParser實現(xiàn)類的映射關系。
  4. 在META-INF/spring.schemas文件中,定義xsd文件全限定名與一個在applicationContext.xml文件中可以配置的命名空間url的映射;
  5. 在META-INF/spring.handlers文件中,定義以上命名空間url和該NamespaceHandler實現(xiàn)類的映射。

到此這篇關于spring的applicationContext.xml文件與NamespaceHandler解析的文章就介紹到這了,更多相關applicationContext與NamespaceHandler解析內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!

相關文章

  • 如何使用SpringMVC的消息轉換器設置日期格式

    如何使用SpringMVC的消息轉換器設置日期格式

    這篇文章主要介紹了如何使用SpringMVC的消息轉換器設置日期格式問題,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教
    2024-07-07
  • SpringBoot實現(xiàn)網(wǎng)站的登陸注冊邏輯記錄

    SpringBoot實現(xiàn)網(wǎng)站的登陸注冊邏輯記錄

    登陸注冊功能是我們日常開發(fā)中經(jīng)常遇到的一個功能,下面這篇文章主要給大家介紹了關于SpringBoot實現(xiàn)網(wǎng)站的登陸注冊邏輯的相關資料,文中通過示例代碼介紹的非常詳細,需要的朋友可以參考下
    2021-10-10
  • Java Builder模式實現(xiàn)原理及優(yōu)缺點解析

    Java Builder模式實現(xiàn)原理及優(yōu)缺點解析

    這篇文章主要介紹了Java Builder模式實現(xiàn)原理及優(yōu)缺點解析,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友可以參考下
    2019-10-10
  • MyBatis實現(xiàn)留言板的示例代碼

    MyBatis實現(xiàn)留言板的示例代碼

    本文主要介紹了MyBatis實現(xiàn)留言板的示例代碼,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2024-08-08
  • Java虛擬機內存分配與回收策略問題精細解讀

    Java虛擬機內存分配與回收策略問題精細解讀

    Java技術體系中所提倡的自動內存管理最終可以歸結為自動化地解決了兩個問題:給對象分配內存以及回收分配給對象的內存,本文讓我們來詳細了解
    2021-11-11
  • Java實現(xiàn)日志文件監(jiān)聽并讀取相關數(shù)據(jù)的方法實踐

    Java實現(xiàn)日志文件監(jiān)聽并讀取相關數(shù)據(jù)的方法實踐

    本文主要介紹了Java實現(xiàn)日志文件監(jiān)聽并讀取相關數(shù)據(jù)的方法實踐,文中通過示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2022-05-05
  • 詳解Java實現(xiàn)多線程的三種方式

    詳解Java實現(xiàn)多線程的三種方式

    這篇文章主要為大家詳細介紹了Java實現(xiàn)多線程的三種方式,感興趣的小伙伴們可以參考一下
    2016-03-03
  • StringUtils,CollectionUtils判斷為空的方法和原生代碼哪個效率最高

    StringUtils,CollectionUtils判斷為空的方法和原生代碼哪個效率最高

    這篇文章主要介紹了StringUtils,CollectionUtils判斷為空的方法和原生代碼哪個效率最高,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2022-02-02
  • springboot中使用groovy的示例代碼

    springboot中使用groovy的示例代碼

    Groovy就是一種繼承了動態(tài)語言的優(yōu)良特性并運行在JVM上的編程語言,Groovy支持動態(tài)輸入,閉包,元編程,運算符重載等等語法,這篇文章主要介紹了springboot中使用groovy的相關知識,需要的朋友可以參考下
    2022-09-09
  • Java多態(tài)的全面系統(tǒng)解析

    Java多態(tài)的全面系統(tǒng)解析

    多態(tài)就是指程序中定義的引用變量所指向的具體類型和通過該引用變量發(fā)出的方法調用在編程時并不確定,而是在程序運行期間才確定,即一個引用變量到底會指向哪個類的實例對象,該引用變量發(fā)出的方法調用到底是哪個類中實現(xiàn)的方法,必須在由程序運行期間才能決定
    2022-03-03

最新評論