在 Dubbo 中,可使用 XML 配置相关信息,也能够用来引入服务或者导出服务。配置完成,启动工程,Spring 会读取配置文件,生成注入 相关 Bean。那 Dubbo 如何实现自定义 XML 被 Spring 加载读取?html
Spring XML Schema 扩展机制。从 Spring 2.0 开始,Spring 开始提供了一种基于 XML Schema 格式扩展机制,用于定义和配置 bean。java
实现 Spring XML Schema 扩展,其实很是简单,只须要完成下面四步。spring
BeanDefinitionParser
。NamespaceHandler
实现类。NamespaceHandler
以及 XSD 文件。咱们按照以上步骤,最终完整 Spring 解析以下配置。缓存
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:demo="http://www.test.com/demo" xsi:schemaLocation="http://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd http://www.test.com/demo http://www.test.com/demo/demo.xsd"> <demo:application name="test" id="test"/> </beans>
XSD 文件,主要用来定义 XML 格式,用来验证 XML 合法性。在 IDE 中,导入 XSD 文件,编辑 XML 文件能够得到相关提示。app
下面咱们生成一个 XSD 文件。ide
<?xml version="1.0" encoding="UTF-8"?> <xsd:schema xmlns="http://www.test.com/demo" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:beans="http://www.springframework.org/schema/beans" targetNamespace="http://www.test.com/demo" elementFormDefault="qualified" attributeFormDefault="unqualified"> <xsd:import namespace="http://www.springframework.org/schema/beans"/> <xsd:element name="application"> <xsd:complexType> <xsd:complexContent> <xsd:extension base="beans:identifiedType"> <xsd:attribute name="name" type="xsd:string" use="required"/> </xsd:extension> </xsd:complexContent> </xsd:complexType> </xsd:element> </xsd:schema>
上面 XSD 文件中 http://www.test.com/demo 为自定义命名空间地址,下面将会使用到。测试
这里实现 BeanDefinitionParser,真正解析 XML 动做在这里完成。ui
因为上面的例子比较简单,咱们能够直接继承 Spring 提供的抽象类 AbstractSingleBeanDefinitionParser
,而后实现相关方法就能够了。spa
public class DemoBeanDefinitionParser extends AbstractSingleBeanDefinitionParser { /** * 返回最会须要注入 Spring Bean 的类型 * @param element * @return */ @Override protected Class<?> getBeanClass(Element element) { return DemoApplication.class; } /*** * 这个方法完成真正解析动做 * @param element * @param builder */ @Override protected void doParse(Element element, BeanDefinitionBuilder builder) { String name=element.getAttribute("name"); builder.addPropertyValue("name",name); } }
固然也能够直接实现 BeanDefinitionParser,这样更加灵活,可是这样相比于上面这个就比较复杂了。code
public class BeanApplicationDefinitionParser implements BeanDefinitionParser { @Override public BeanDefinition parse(Element element, ParserContext parserContext) { String name=element.getAttribute("name"); // Bean 定义,最后根据这个生产 Bean RootBeanDefinition rootBeanDefinition=new RootBeanDefinition(); rootBeanDefinition.setBeanClass(DemoApplication.class); rootBeanDefinition.setLazyInit(false); // 添加解析的属性 rootBeanDefinition.getPropertyValues().add("name",name); // 将生成的 BeanDefinition 注册,少了这一步将会致使最后生成 Bean 时报错 parserContext.getRegistry().registerBeanDefinition("application",rootBeanDefinition); return rootBeanDefinition; } }
这一步实现 NamespaceHandler,开发者自定义 NamespaceHandler 只要继承 NamespaceHandlerSupport
抽象类,实现 init
方法。在这个方法中注册上面一步实现 BeanDefinitionParser
。
public class DemoNameSpaceHandler extends NamespaceHandlerSupport { @Override public void init() { // elementName 为命名空间 registerBeanDefinitionParser("application",new BeanApplicationDefinitionParser()); } }
这一步咱们须要在 META-INF 中生成两个配置文件,分别为 spring.handlers
,spring.schemas
。
spring.schemas
指定 XSD 文件路径。
http\://www.test.com/demo/demo.xsd=com/spring/learning/xml/schemas/autoring/leanrn/demo.xsd
spring.handlers
指定 NamespaceHandler
完整类名,既包含前面的包名。
这里须要注意的是
:
须要进行转义
首先咱们生产 Spring XML 配置文件。
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:demo="http://www.test.com/demo" xsi:schemaLocation="http://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd http://www.test.com/demo http://www.test.com/demo/demo.xsd"> <demo:application name="test" id="test"/> </beans>
这里须要注意须要使用 XSD 文件中定义 http://www.test.com/demo
。
接着咱们使用 SpringBoot ,导入 XML 文件,而后运行。
@SpringBootApplication @ImportResource(locations = {"classpath:applicationContext.xml"}) public class XmlSchemaApplication { public static void main(String[] args) { ConfigurableApplicationContext applicationContext = SpringApplication.run(XmlSchemaApplication.class, args); DemoApplication demoApplication=applicationContext.getBean(DemoApplication.class); System.out.println("application name is "+demoApplication.getName()); } }
输出结果为:
application name is test
这里咱们主要研究自定义 XML 扩展文件如何被 Spring 加载。
Spring 启动过程当中会经过 BeanDefinitionDocumentReader
读取 beans 标签里面全部配置,这个过程将会经过 BeanDefinitionParserDelegate#parseCustomElement
解析自定义元素。
上面解析过程能够得到自定义 NamespaceHandler
,而后调用 parse
方法解析。
接着咱们查看 NamespaceHandlerResolver#resolve
方法,查看如何获取自定义 NamespaceHandler
。
在这个方法中,主要是从 handlerMappings
缓存中获取 NamespaceHandler
。而该缓存来源于 getHandlerMappings
方法,这个方法将会加载咱们上面自定义 spring.handlers
文件。
看完 Spring 加载 NamespaceHandler
过程,下面咱们查看最重要 BeanDefinition
如何生成。
上面已经讲到 Spring 会使用 NamespaceHandler.parse
解析,因为咱们继承了 NamespaceHandlerSupport
,查看里面具体实现。
获取到 BeanDefinition 会将其注册到容器中,而后会经过 BeanDefinition
生成 Bean。这个生成过程不属于本章节内容,因此再也不概述,感兴趣同窗能够自行搜索。
最后咱们查看 Dubbo XML Schema 扩展如何实现。
能够看到 Dubbo XML Schema 扩展恰好对应 Spring 四个标准的步骤。
最后用一张图片总结全文内容。
xsd-custom-registration
Spring中的XML schema扩展机制