1、Schema自定义扩展步骤:
-
创建一个 XML Schema 文件,描述自定义的合法构建模块,也就是xsd文件
-
自定义个处理器类,并实现
NamespaceHandler
接口(比较容易) -
自定义一个或多个解析器,实现
BeanDefinitionParser
接口(最关键的部分) -
注册上面的组件到Spring IOC容器中
2、自定义 XML Schema 文件
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<xsd:schema xmlns="http://www.ctrip.com/schema/apollo"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
targetNamespace="http://www.ctrip.com/schema/apollo"
elementFormDefault="qualified"
attributeFormDefault="unqualified">
<xsd:annotation>
<xsd:documentation><![CDATA[ Namespace support for Ctrip Apollo Configuration Center. ]]></xsd:documentation>
</xsd:annotation>
<xsd:element name="config">
<xsd:annotation>
<xsd:documentation>
<![CDATA[ Apollo configuration section to integrate with Spring.]]>
</xsd:documentation>
</xsd:annotation>
<xsd:complexType>
<xsd:attribute name="namespaces" type="xsd:string" use="optional">
<xsd:annotation>
<xsd:documentation>
<![CDATA[
The comma-separated list of namespace names to integrate with Spring property sources.
If not specified, then default to application namespace.
]]>
</xsd:documentation>
</xsd:annotation>
</xsd:attribute>
<xsd:attribute name="order" type="xsd:int" use="optional">
<xsd:annotation>
<xsd:documentation>
<![CDATA[
The order of the config, default to Ordered.LOWEST_PRECEDENCE, which is Integer.MAX_VALUE.
If there are properties with the same name in different apollo configs, the config with smaller order wins.
]]>
</xsd:documentation>
</xsd:annotation>
</xsd:attribute>
</xsd:complexType>
</xsd:element>
</xsd:schema>
代码解释:
代码 | 作用 |
---|---|
| 显示 schema 中用到的元素和数据类型来自命名空间 的元素和数据类型应该使用前缀 xsd |
| 被此 schema 定义的元素 (config, namespaces,order) 来自命名空间 |
| 指出任何 XML 实例文档所使用的且在此 schema 中声明过的元素必须被命名空间限定 |
3、自定义 NamespaceHandler
定义好XML Schema文件,需要定义一个NamespaceHandler解析配置文件。
NamespaceHandler
接口是非常简单的,只有三个方法:
-
init()
:NamespaceHandler
被使用之前调用,完成NamespaceHandler的初始化
-
BeanDefinition parse(Element, ParserContext)
: 当遇到顶层元素时被调用 -
BeanDefinition decorate(Node,BeanDefinitionHandler,ParserContext)
: 当遇到一个属性或者嵌套元素的时候调用
Spring提供了一个默认的实现类NamespaceHandlerSupport,我们只需要在init的时候注册每个元素的解析器即可。
NamespaceHandlerSupport
可以注册任意个BeanDefinitionParser
。NamespaceHandlerSupport
负责所有自定义元素的编排,而解析XML的工作委托给各个BeanDefinitionParser
负责。
4、自定义BeanDefinitionParser
BeanDefinitionParser
将被调用,如果NamespapceHandler
遇到元素类型已经有对应注册的parser(例如上面的handler如果遇到dateformat,DateformatDefinitionParser
会被调用,解析相应的属性设置到Bean中)将会被调用。BeanDefinitionParser
负责解析一个顶级元素。
Spring提供了AbstractSingleBeanDefinitionParser
来处理繁重的解析工作,只需要实现两个方法:
-
Class<?> getBeanClass(Element):返回元素的Class类型
-
void doParse(Element element,BeanDefinitionBuilder builder):添加元素的属性或者构造参数等等。
5、注册handler和schema
为了让Spring在解析xml的时候能够感知到我们的自定义元素,我们需要把namespaceHandler
和xsd文件放到2个指定的配置文件中,这2个文件都位于META-INF
目录中。
5.1spring.handlers
文件包含了xml schema uri 和 Handler类的映射关系,例如
http\://www.ctrip.com/schema/apollo=com.ctrip.framework.apollo.spring.config.NamespaceHandler
5.2 spring.schemas
文件包含了xml schema xsd文件命名空间和文件路径的映射关系,例如
http\://www.ctrip.com/schema/apollo-1.0.0.xsd=/META-INF/apollo-1.0.0.xsd
http\://www.ctrip.com/schema/apollo.xsd=/META-INF/apollo-1.0.0.xsd