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

spring的applicationContext.xml文件與NamespaceHandler解析

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

applicationContext.xml文件解析

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

NamespaceHandler

  • 在Spring的設(shè)計(jì)當(dāng)中,通常每個(gè)標(biāo)簽都屬于一個(gè)特定的名稱空間來(lái)避免名稱沖突,如context名稱空間,mvc名稱空間等,每個(gè)名稱空間內(nèi)部可定義多個(gè)標(biāo)簽。
  • 使用NamespaceHandler接口來(lái)維護(hù)每個(gè)名稱空間內(nèi)部的標(biāo)簽 和標(biāo)簽處理器之間的映射關(guān)系。這樣X(jué)mlBeanDefinitionReader在解析applicationContext.xml文件時(shí),遇到某個(gè)名稱空間,則獲取這名稱空間對(duì)應(yīng)的NamespaceHandler,然后通過(guò)NamespaceHandler進(jìn)一步獲取內(nèi)部標(biāo)簽對(duì)應(yīng)的標(biāo)簽處理器。

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

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

對(duì)應(yīng)的NamespaceHandler的實(shí)現(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)建一個(gè)Document對(duì)象,交給子組件BeanDefinitionDocumentReader處理這個(gè)Document對(duì)象。而NamespaceHandler的實(shí)現(xiàn)類主要是在BeanDefinitionDocumentReader中在解析Document對(duì)象的Element元素時(shí)調(diào)用,如下:
public BeanDefinition parseCustomElement(Element ele, @Nullable BeanDefinition containingBd) {
	String namespaceUri = getNamespaceURI(ele);
	if (namespaceUri == null) {
		return null;
	}
	// 獲取一個(gè)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;
	}
	// 通過(guò)這個(gè)NamespaceHandler
	// 在它里面維護(hù)的parser集合中找到
	// 與該標(biāo)簽對(duì)應(yīng)的parser,由該parser來(lái)執(zhí)行解析
	return handler.parse(ele, new ParserContext(this.readerContext, this, containingBd));
}
  • 以上已經(jīng)說(shuō)明了通過(guò)XmlBeanDefinitionReader的NamespaceHandlerResolver維護(hù):名稱空間和NamespaceHandler的映射;通過(guò)NamespaceHandler來(lái)維護(hù)標(biāo)簽和Parser的映射,那么兩者是什么時(shí)候初始化注冊(cè)的呢?
  • 其實(shí)NamespaceHandler和Parser的初始化,使用的是懶加載機(jī)制,即當(dāng)調(diào)用了NamespaceHandlerResolver的resolve方法時(shí),才進(jìn)行加載,加載之后進(jìn)行緩存。如下:

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

在resolve方法中調(diào)用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文件加載鍵值對(duì),并緩存在類型為ConcurrentHashMap的handlerMappings中;
  2. 注意這里并沒(méi)有初始化NamespaceHandler,即handlerMappings的value還是String類型。

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

  /**
   * 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;
  	}
  	// 不是第一次調(diào)用,則已經(jīng)是NamespaceHandler類型了,可以直接返回
  	else if (handlerOrClassName instanceof NamespaceHandler) {
  		return (NamespaceHandler) handlerOrClassName;
  	}
  	// 第一次調(diào)用,由上面分析可知:
  	// 剛開(kāi)始從META-INF/spring.handlers
  	// 讀出時(shí),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);
  			// 調(diào)用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方法實(shí)現(xiàn):各個(gè)NamespaceHandler接口實(shí)現(xiàn)類,在init方法中注冊(cè)xml的標(biāo)簽和Parser之間的映射關(guān)系:如下為context標(biāo)簽的名稱空間處理器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());
	}
}

插件機(jī)制拓展支持

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

基本步驟包括:

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

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

相關(guān)文章

  • 如何使用SpringMVC的消息轉(zhuǎn)換器設(shè)置日期格式

    如何使用SpringMVC的消息轉(zhuǎn)換器設(shè)置日期格式

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

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

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

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

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

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

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

    Java虛擬機(jī)內(nèi)存分配與回收策略問(wèn)題精細(xì)解讀

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

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

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

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

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

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

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

    springboot中使用groovy的示例代碼

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

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

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

最新評(píng)論