Spring XML Schema擴展機制源碼解讀

{"type":"doc","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"在","attrs":{}},{"type":"link","attrs":{"href":"https://xie.infoq.cn/article/37bad125278f030b476d62584","title":"","type":null},"content":[{"type":"text","text":"聊聊 Spring 的 XML Schema 擴展機制的使用方式","attrs":{}}]},{"type":"text","text":"中介紹瞭如何通過xml自定義標籤進行spring擴展,在各類組件(Redis,Mybatis,Dubbo)需要和Spring進行整合使用時都會用到。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"本文將從Spring源碼中尋找xml自定義標籤生效的原因,實際上,在源碼中可以發現Spring將xml標籤分成了兩類,一類是spring自定義的標籤;另一類則是擴展自定義標籤,如spring事務標籤等,以及前面文章中介紹的用戶自定義的標籤都屬於擴展自定義標籤。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"blockquote","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"閱讀本文前建議可先查看","attrs":{}},{"type":"link","attrs":{"href":"https://xie.infoq.cn/article/37bad125278f030b476d62584","title":"","type":null},"content":[{"type":"text","text":"聊聊 Spring 的 XML Schema 擴展機制的使用方式","attrs":{}}]}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"本文中spring源碼版本爲4.3.13-RELEASE","attrs":{}}]}],"attrs":{}},{"type":"heading","attrs":{"align":null,"level":1},"content":[{"type":"text","text":"源碼解析","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"從容器啓動作爲入口,如下所示啓動代碼爲","attrs":{}},{"type":"link","attrs":{"href":"https://xie.infoq.cn/article/37bad125278f030b476d62584","title":"","type":null},"content":[{"type":"text","text":"聊聊 Spring 的 XML Schema 擴展機制的使用方式","attrs":{}}]},{"type":"text","text":"一文中的啓動代碼","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"java"},"content":[{"type":"text","text":"public class App {\n public static void main(String[] args) {\n ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext(\"spring-service.xml\");\n DistributedIdComponent bean = context.getBean(DistributedIdComponent.class);\n\n String id = bean.generateId();\n\n System.out.println(\"id:\" + id);\n }\n}\n","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"第一行代碼","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext(\"spring-service.xml\")","attrs":{}}],"attrs":{}},{"type":"text","text":" 即容器初始化,包括解析xml、加載bean等,","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"ClassPathXmlApplicationContext","attrs":{}}],"attrs":{}},{"type":"text","text":"是BeanFactory的實現類。","attrs":{}}]},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"ClassPathXmlApplicationContext","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"以ClassPathXmlApplicationContext的構造方法爲入口,如下:","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"java"},"content":[{"type":"text","text":"public ClassPathXmlApplicationContext(String configLocation) throws BeansException {\n this(new String[] {configLocation}, true, null);\n }\n\npublic ClassPathXmlApplicationContext(String[] configLocations, boolean refresh, ApplicationContext parent)\n throws BeansException {\n\n super(parent);\n setConfigLocations(configLocations);\n if (refresh) {\n refresh();\n }\n }\n","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"由於整個過程涉及到的源碼層級較深,類較多,爲了方法來回查看大致做了如下一個時序圖:","attrs":{}}]},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/8b/8b1de9fe5feea7f9c4450cf079a308a1.png","alt":null,"title":null,"style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"實際上到DefaultBeanDefinitionDocumentReader類往後涉及到具體的從xml標籤解析成BeanDefinition還有一些步驟沒有在上時序圖中繼續展開,下面會從parseCustomElement往後的流程進行詳細介紹。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"爲方便了解上圖中給類與類之間的關係,可查看如下UML類圖:","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/18/188c115c08b385edc65a68a3dbb7a9ec.png","alt":null,"title":"","style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":"","fromPaste":false,"pastePass":false}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"heading","attrs":{"align":null,"level":1},"content":[{"type":"text","text":"DefaultBeanDefinitionDocumentReader","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"如上類圖中所示","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"DefaultBeanDefinitionDocumentReader","attrs":{}}],"attrs":{}},{"type":"text","text":"是接口","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"BeanDefinitionDocumentReader","attrs":{}}],"attrs":{}},{"type":"text","text":"的實現類,用於從XML中讀取bean definition。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"如下源碼所示,在","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"doRegisterBeanDefinitions","attrs":{}}],"attrs":{}},{"type":"text","text":"方法中要注意兩個地方,一個是創建了一個委派類BeanDefinitionParserDelegate;一個是parseBeanDefinitions(root, this.delegate),爲具體解析BeanDefinition的方法。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"java"},"content":[{"type":"text","text":" // DefaultBeanDefinitionDocumentReader.java\n \n /**\n * Register each bean definition within the given root {@code } element.\n */\n protected void doRegisterBeanDefinitions(Element root) {\n // Any nested elements will cause recursion in this method. In\n // order to propagate and preserve default-* attributes correctly,\n // keep track of the current (parent) delegate, which may be null. Create\n // the new (child) delegate with a reference to the parent for fallback purposes,\n // then ultimately reset this.delegate back to its original (parent) reference.\n // this behavior emulates a stack of delegates without actually necessitating one.\n BeanDefinitionParserDelegate parent = this.delegate;\n this.delegate = createDelegate(getReaderContext(), root, parent);\n\n if (this.delegate.isDefaultNamespace(root)) {\n String profileSpec = root.getAttribute(PROFILE_ATTRIBUTE);\n if (StringUtils.hasText(profileSpec)) {\n String[] specifiedProfiles = StringUtils.tokenizeToStringArray(\n profileSpec, BeanDefinitionParserDelegate.MULTI_VALUE_ATTRIBUTE_DELIMITERS);\n if (!getReaderContext().getEnvironment().acceptsProfiles(specifiedProfiles)) {\n if (logger.isInfoEnabled()) {\n logger.info(\"Skipped XML bean definition file due to specified profiles [\" + profileSpec +\n \"] not matching: \" + getReaderContext().getResource());\n }\n return;\n }\n }\n }\n\n preProcessXml(root);\n // 解析xml中的BeanDefinition\n parseBeanDefinitions(root, this.delegate);\n postProcessXml(root);\n\n this.delegate = parent;\n }\n\n /**\n * Parse the elements at the root level in the document:\n * \"import\", \"alias\", \"bean\".\n * @param root the DOM root element of the document\n */\n protected void parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate) {\n if (delegate.isDefaultNamespace(root)) {\n NodeList nl = root.getChildNodes();\n for (int i = 0; i < nl.getLength(); i++) {\n Node node = nl.item(i);\n if (node instanceof Element) {\n Element ele = (Element) node;\n if (delegate.isDefaultNamespace(ele)) {\n // 解析默認標籤\n parseDefaultElement(ele, delegate);\n }\n else {\n // 解析自定義(擴展)標籤\n delegate.parseCustomElement(ele);\n }\n }\n }\n }\n else {\n // 解析自定義(擴展)標籤\n delegate.parseCustomElement(root);\n }\n }\n","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"從parseBeanDefinitions方法中的邏輯可以看出,最終會有兩個分支,一個是解析默認標籤;一個是解析自定義(擴展)標籤,這裏直接看parseCustomElement:","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"java"},"content":[{"type":"text","text":" // BeanDefinitionParserDelegate.java \n\n public BeanDefinition parseCustomElement(Element ele) {\n return parseCustomElement(ele, null);\n }\n\n public BeanDefinition parseCustomElement(Element ele, BeanDefinition containingBd) {\n String namespaceUri = getNamespaceURI(ele);\n NamespaceHandler handler = this.readerContext.getNamespaceHandlerResolver().resolve(namespaceUri);\n if (handler == null) {\n error(\"Unable to locate Spring NamespaceHandler for XML schema namespace [\" + namespaceUri + \"]\", ele);\n return null;\n }\n return handler.parse(ele, new ParserContext(this.readerContext, this, containingBd));\n }\n","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"關鍵的一行代碼爲","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"NamespaceHandler handler = this.readerContext.getNamespaceHandlerResolver().resolve(namespaceUri)","attrs":{}}],"attrs":{}},{"type":"text","text":",獲取對應的NamespaceHandler類。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"其中","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"this.readerContext","attrs":{}}],"attrs":{}},{"type":"text","text":"是在XmlBeanDefinitionReader中registerBeanDefinitions的方法中實例化XmlReaderContext然後傳遞下來的(可查看第一張時序圖來定位到此方法在整個流程中的位置),如下:","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"java"},"content":[{"type":"text","text":"// XmlBeanDefinitionReader.java\n\npublic int registerBeanDefinitions(Document doc, Resource resource) throws BeanDefinitionStoreException {\n BeanDefinitionDocumentReader documentReader = createBeanDefinitionDocumentReader();\n int countBefore = getRegistry().getBeanDefinitionCount();\n // createReaderContext見下面的方法\n documentReader.registerBeanDefinitions(doc, createReaderContext見下面的方法(resource));\n return getRegistry().getBeanDefinitionCount() - countBefore;\n }\n\n// 實例化XmlReaderContext\npublic XmlReaderContext createReaderContext(Resource resource) {\n return new XmlReaderContext(resource, this.problemReporter, this.eventListener,\n this.sourceExtractor, this, getNamespaceHandlerResolver());\n}\n\n// 創建DefaultNamespaceHandlerResolver\npublic NamespaceHandlerResolver getNamespaceHandlerResolver() {\n if (this.namespaceHandlerResolver == null) {\n this.namespaceHandlerResolver = createDefaultNamespaceHandlerResolver();\n }\n return this.namespaceHandlerResolver;\n }\n\nprotected NamespaceHandlerResolver createDefaultNamespaceHandlerResolver() {\n return new DefaultNamespaceHandlerResolver(getResourceLoader().getClassLoader());\n }\n","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"從而可以得出","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"this.readerContext.getNamespaceHandlerResolver()","attrs":{}}],"attrs":{}},{"type":"text","text":"返回的就是","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"DefaultNamespaceHandlerResolver","attrs":{}}],"attrs":{}},{"type":"text","text":"實例,進而查看","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"DefaultNamespaceHandlerResolver","attrs":{}}],"attrs":{}},{"type":"text","text":"的resolve(namespaceUri)方法,","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"java"},"content":[{"type":"text","text":" // DefaultNamespaceHandlerResolver.java \n\n @Override\n public NamespaceHandler resolve(String namespaceUri) {\n Map handlerMappings = getHandlerMappings();\n Object handlerOrClassName = handlerMappings.get(namespaceUri);\n if (handlerOrClassName == null) {\n return null;\n }\n else if (handlerOrClassName instanceof NamespaceHandler) {\n return (NamespaceHandler) handlerOrClassName;\n }\n else {\n String className = (String) handlerOrClassName;\n try {\n Class> handlerClass = ClassUtils.forName(className, this.classLoader);\n if (!NamespaceHandler.class.isAssignableFrom(handlerClass)) {\n throw new FatalBeanException(\"Class [\" + className + \"] for namespace [\" + namespaceUri +\n \"] does not implement the [\" + NamespaceHandler.class.getName() + \"] interface\");\n }\n NamespaceHandler namespaceHandler = (NamespaceHandler) BeanUtils.instantiateClass(handlerClass);\n namespaceHandler.init();\n handlerMappings.put(namespaceUri, namespaceHandler);\n return namespaceHandler;\n }\n catch (ClassNotFoundException ex) {\n throw new FatalBeanException(\"NamespaceHandler class [\" + className + \"] for namespace [\" +\n namespaceUri + \"] not found\", ex);\n }\n catch (LinkageError err) {\n throw new FatalBeanException(\"Invalid NamespaceHandler class [\" + className + \"] for namespace [\" +\n namespaceUri + \"]: problem with handler class file or dependent class\", err);\n }\n }\n }\n\n /**\n * Load the specified NamespaceHandler mappings lazily.\n */\n private Map getHandlerMappings() {\n if (this.handlerMappings == null) {\n synchronized (this) {\n if (this.handlerMappings == null) {\n try {\n Properties mappings =\n PropertiesLoaderUtils.loadAllProperties(this.handlerMappingsLocation, this.classLoader);\n if (logger.isDebugEnabled()) {\n logger.debug(\"Loaded NamespaceHandler mappings: \" + mappings);\n }\n Map handlerMappings = new ConcurrentHashMap(mappings.size());\n CollectionUtils.mergePropertiesIntoMap(mappings, handlerMappings);\n this.handlerMappings = handlerMappings;\n }\n catch (IOException ex) {\n throw new IllegalStateException(\n \"Unable to load NamespaceHandler mappings from location [\" + this.handlerMappingsLocation + \"]\", ex);\n }\n }\n }\n }\n return this.handlerMappings;\n }\n","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"handlerMappingsLocation默認取","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"META-INF/spring.handlers","attrs":{}}],"attrs":{}},{"type":"text","text":",通過上述的getHandlerMappings()方法將","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"META-INF/spring.handlers","attrs":{}}],"attrs":{}},{"type":"text","text":"裏配置的信息以map的結構保存在","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"handlerMappings","attrs":{}}],"attrs":{}},{"type":"text","text":"中,例如spring-aop的spring-handlers文件中配置如下:","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"properties"},"content":[{"type":"text","text":"http\\://www.springframework.org/schema/aop=org.springframework.aop.config.AopNamespaceHandler\n","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"在此處會將http://www.springframework.org/schema/aop作爲map的key,org.springframework.aop.config.AopNamespaceHandler爲對應的value。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"因此,回到BeanDefinitionParserDelegate的parseCustomElement方法中,","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"java"},"content":[{"type":"text","text":"// BeanDefinitionParserDelegate.java \n\n public BeanDefinition parseCustomElement(Element ele) {\n return parseCustomElement(ele, null);\n }\n\n public BeanDefinition parseCustomElement(Element ele, BeanDefinition containingBd) {\n String namespaceUri = getNamespaceURI(ele);\n // this.readerContext.getNamespaceHandlerResolver()對應爲DefaultNamespaceHandlerResolver\n // 通過DefaultNamespaceHandlerResolver的resolve方法,會從META-INF/spring.handlers中的配置獲取到對應的NamespaceHandler實現類\n NamespaceHandler handler = this.readerContext.getNamespaceHandlerResolver().resolve(namespaceUri);\n if (handler == null) {\n error(\"Unable to locate Spring NamespaceHandler for XML schema namespace [\" + namespaceUri + \"]\", ele);\n return null;\n }\n // 使用自定義NamespaceHandler實現類進行解析\n return handler.parse(ele, new ParserContext(this.readerContext, this, containingBd));\n }\n","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"一般通過繼承抽象類","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"NamespaceHandlerSupport","attrs":{}}],"attrs":{}},{"type":"text","text":"\t(","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"NamespaceHandlerSupport","attrs":{}}],"attrs":{}},{"type":"text","text":"繼承自接口","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"NamespaceHandler","attrs":{}}],"attrs":{}},{"type":"text","text":")來通過registerBeanDefinitionParser註冊一個自定義的BeanDefinitionParser。然後上述","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"handler.parse會先從註冊過的中找到對應uri對應的BeanDefinitionParser,最後進行解析成BeanDefinition,","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"以下以AopNamespaceHandler爲例進行說明:","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"java"},"content":[{"type":"text","text":"// 1.註冊BeanDefinitionParser\n\npublic class AopNamespaceHandler extends NamespaceHandlerSupport {\n public AopNamespaceHandler() {\n }\n\n public void init() {\n // 調用NamespaceHandlerSupport的registerBeanDefinitionParser進行註冊BeanDefinitionParser\n this.registerBeanDefinitionParser(\"config\", new ConfigBeanDefinitionParser());\n this.registerBeanDefinitionParser(\"aspectj-autoproxy\", new AspectJAutoProxyBeanDefinitionParser());\n this.registerBeanDefinitionDecorator(\"scoped-proxy\", new ScopedProxyBeanDefinitionDecorator());\n this.registerBeanDefinitionParser(\"spring-configured\", new SpringConfiguredBeanDefinitionParser());\n }\n}\n\n// abstract class NamespaceHandlerSupport\n// parsers屬性保存映射關係\nprivate final Map parsers =\n new HashMap();\n\n// 上面init方法調用時寫入屬性parsers中\nprotected final void registerBeanDefinitionParser(String elementName, BeanDefinitionParser parser) {\n this.parsers.put(elementName, parser);\n }\n","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"完成了BeanDefinitionParser的註冊和映射關係保存,則方便後續的解析:","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"java"},"content":[{"type":"text","text":"// abstract class NamespaceHandlerSupport\n\n @Override\n public BeanDefinition parse(Element element, ParserContext parserContext) {\n // 獲取到BeanDefinitionParser,並調用其parse方法\n return findParserForElement(element, parserContext).parse(element, parserContext);\n }\n\nprivate BeanDefinitionParser findParserForElement(Element element, ParserContext parserContext) {\n // 獲取名稱如aspectj-autoproxy\n String localName = parserContext.getDelegate().getLocalName(element);\n // 獲取到對應的BeanDefinitionParser 如AspectJAutoProxyBeanDefinitionParser\n BeanDefinitionParser parser = this.parsers.get(localName);\n if (parser == null) {\n parserContext.getReaderContext().fatal(\n \"Cannot locate BeanDefinitionParser for element [\" + localName + \"]\", element);\n }\n return parser;\n }\n","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"至此,對 spring容器是如何加載並解析自定義標籤的過程基本分析完成。","attrs":{}}]},{"type":"heading","attrs":{"align":null,"level":1},"content":[{"type":"text","text":"總結","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"通過對 spring容器是如何加載並解析自定義標籤的過程的源碼過程進行閱讀分析,瞭解自定義標籤生效的原因,相應的spring是如何對xml的配置進行解析爲bean definition的過程也大致可以瞭解。上述整個過程完成是跟着spring源碼調用層級展開,沒有具體瞭解源碼爲什麼是這樣進行設計,比如過程中有用到設計模式委派模式等,後續可在此基礎上進行進一步的學習。","attrs":{}}]}]}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章