Spring中的NamespaceHandler加載過(guò)程源碼詳解
NamespaceHandler加載過(guò)程流程
流程圖中羅列了Spring加載配置的整個(gè)過(guò)程,其中,從BeanDefinitionParserDelegate.parseCustomElement(...)開(kāi)始,即開(kāi)始了對(duì)命名空間NamespaceHandler的解析,本文對(duì)這部分內(nèi)容進(jìn)行解析。
NamespaceHandler加載過(guò)程解析
1) BeanDefinitionParserDelegate.parseCustomElement(…)方法
① 取得指定元素的命名空間。
② 通過(guò)DefaultNamespaceHandlerResolver解析指定元素命名空間對(duì)應(yīng)的NamespaceHandler。
③ 通過(guò)查找的NamespaceHandler解析指定元素,取得Bean定義實(shí)例。
/** * 解析自定義元素. * @param ele 元素. * @param containingBd Bean定義. * @return 解析Bean定義. */ @Nullable public BeanDefinition parseCustomElement(Element ele, @Nullable BeanDefinition containingBd) { // 獲取元素命名空間. String namespaceUri = getNamespaceURI(ele); if (namespaceUri == null) { return null; } // 解析元素命名空間對(duì)應(yīng)的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; } // 解析當(dāng)前元素. return handler.parse(ele, new ParserContext(this.readerContext, this, containingBd)); }
2) DefaultNamespaceHandlerResolver.resolve(…)方法
① 加載所有依賴的META-INF/spring.handlers文件,取得命名空間對(duì)應(yīng)處理器映射。
② 根據(jù)命名空間從①的映射中查找對(duì)應(yīng)的NamespaceHandler類。
③ 映射配置的NamespaceHandler類必須實(shí)現(xiàn)NamespaceHandler接口,否則拋出異常。
④ 根據(jù)配置映射的NamespaceHandler類路徑進(jìn)行實(shí)例化。
⑤ 調(diào)用NamespaceHandler的init()方法,指定命名空間元素對(duì)應(yīng)的解析器。
/** * 從配置映射中查找所提供命名空間URI的NamespaceHandler. * @param namespaceUri 相關(guān)命名空間URI. * @return NamespaceHandler,若未找到,則為null. */ @Override @Nullable public NamespaceHandler resolve(String namespaceUri) { // 加載處理器映射. Map<String, Object> handlerMappings = getHandlerMappings(); // 根據(jù)namespaceUri查找處理器類路徑. Object handlerOrClassName = handlerMappings.get(namespaceUri); if (handlerOrClassName == null) { return null; } else if (handlerOrClassName instanceof NamespaceHandler) { return (NamespaceHandler) handlerOrClassName; } else { String className = (String) handlerOrClassName; try { Class<?> handlerClass = ClassUtils.forName(className, this.classLoader); // 處理器需實(shí)現(xiàn)NamespaceHandler接口. 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); // NamespaceHandler初始化,指定命名空間下各元素對(duì)應(yīng)的解析器. 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); } } }
3) DefaultNamespaceHandlerResolver.getHandlerMappings()方法
① 加載所有依賴的META-INF/spring.handlers文件,取得命名空間對(duì)應(yīng)處理器映射,存儲(chǔ)在Properties實(shí)例中。
② 將數(shù)據(jù)由Properties轉(zhuǎn)存到Map中。
/** * 延遲加載指定的NamespaceHandler映射. */ private Map<String, Object> getHandlerMappings() { Map<String, Object> handlerMappings = this.handlerMappings; if (handlerMappings == null) { synchronized (this) { handlerMappings = this.handlerMappings; if (handlerMappings == null) { try { // 搜索META-INF/spring.handlers文件. Properties mappings = PropertiesLoaderUtils.loadAllProperties(this.handlerMappingsLocation, this.classLoader); if (logger.isDebugEnabled()) { logger.debug("Loaded NamespaceHandler mappings: " + mappings); } Map<String, Object> mappingsToUse = new ConcurrentHashMap<>(mappings.size()); // 將Properties數(shù)據(jù)轉(zhuǎn)換到Map中. CollectionUtils.mergePropertiesIntoMap(mappings, mappingsToUse); handlerMappings = mappingsToUse; this.handlerMappings = handlerMappings; } catch (IOException ex) { throw new IllegalStateException( "Unable to load NamespaceHandler mappings from location [" + this.handlerMappingsLocation + "]", ex); } } } } return handlerMappings; }
4) NamespaceHandlerSupport.parse(…)方法
① 使用提供元素的本地名稱查找BeanDefinitionParser。
② 調(diào)用BeanDefinitionParser實(shí)現(xiàn)進(jìn)行解析。
/** * 通過(guò)委托給為Element注冊(cè)的BeanDefinitionParser來(lái)解析提供的Element. */ @Override @Nullable public BeanDefinition parse(Element element, ParserContext parserContext) { // 使用提供元素的本地名稱查找BeanDefinitionParser. BeanDefinitionParser parser = findParserForElement(element, parserContext); // 調(diào)用BeanDefinitionParser實(shí)現(xiàn)進(jìn)行解析. return (parser != null ? parser.parse(element, parserContext) : null); }
5) NamespaceHandlerSupport.findParserForElement(…)方法
① 通過(guò)指定元素,取得元素的本地參數(shù)名稱。
② 根據(jù)本地名稱查找已注冊(cè)的BeanDefinitionParser。
/** * 使用提供的元素的本地名稱查找BeanDefinitionParser. */ @Nullable private BeanDefinitionParser findParserForElement(Element element, ParserContext parserContext) { // 獲取提供元素的本地名稱. String localName = parserContext.getDelegate().getLocalName(element); // 根據(jù)本地名稱查找BeanDefinitionParser. BeanDefinitionParser parser = this.parsers.get(localName); if (parser == null) { parserContext.getReaderContext().fatal( "Cannot locate BeanDefinitionParser for element [" + localName + "]", element); } return parser; }
6) BeanDefinitionParser.parse(…)方法
BeanDefinitionParser.parse(...)是由具體開(kāi)發(fā)進(jìn)行編寫的,其中涉及元素解析、元素校驗(yàn)、注冊(cè)對(duì)應(yīng)Beam。
總結(jié)
‘工欲善其事必先利其器’,只有當(dāng)對(duì)原理的了解達(dá)到一定程度,才能在實(shí)際遇到問(wèn)題,簡(jiǎn)潔、快速、高效的解決問(wèn)題。
源碼解析基于spring-framework-5.0.5.RELEASE版本源碼。
若文中存在錯(cuò)誤和不足,歡迎指正!
到此這篇關(guān)于Spring中的NamespaceHandler加載過(guò)程源碼詳解的文章就介紹到這了,更多相關(guān)NamespaceHandler加載過(guò)程內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Mybatis的update更新批量與普通解決方式對(duì)比
這篇文章主要為大家介紹了Mybatis的update更新批量與普通解決方式對(duì)比,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-04-04一篇超詳細(xì)的SpringBoot整合MybatisPlus的文章
這篇文章主要介紹了springboot整合Mybatis-plus的實(shí)現(xiàn),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2021-07-07java高并發(fā)InterruptedException異常引發(fā)思考
這篇文章主要為大家介紹了java高并發(fā)InterruptedException異常引發(fā)思考,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-08-08microlog4android將Android Log日志寫到SD卡文件中實(shí)現(xiàn)方法
這篇文章主要介紹了microlog4android將Android Log日志寫到SD卡文件中實(shí)現(xiàn)方法的相關(guān)資料,需要的朋友可以參考下2016-10-10解決Mybatis-plus和pagehelper依賴沖突的方法示例
這篇文章主要介紹了解決Mybatis-plus和pagehelper依賴沖突的方法示例,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2021-04-04Java中一個(gè)線程執(zhí)行死循環(huán)有什么后果
這篇文章主要為大家詳細(xì)介紹了Java中一個(gè)線程執(zhí)行死循環(huán)有什么后果,當(dāng)一個(gè)線程在執(zhí)行死循環(huán)時(shí)會(huì)影響另外一個(gè)線程嗎,下面為大家揭曉2016-05-05