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":{}}]}]}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章