SpringBoot 自定义Schema扩展
最近在写RPC框架时,用到了自定义的xsd配置。我们平时习惯于使用bean配置实例化对象,因此把xsd这种方式单独拎出来。
1. 配置ServiceConfig属性
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
|
@Data public class ServiceConfig { /** 接口 */ private String interfaceClass; /** 引用 */ private String ref; /** 版本 */ private String version; @Override public String toString() { return "ServiceConfig{" + "interfaceClass='" + interfaceClass + '\ '' + ", ref='" + ref + '\ '' + ", version='" + version + '\ '' + '}' ; } } |
2. 编写XSD文件
配置element的name为service,配置的attribute对应ServiceConfig定义的属性
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
|
<? xml version = "1.0" encoding = "UTF-8" ?> < xsd:schema xmlns = "http://gitee.com/schema/link" xmlns:xsd = "http://www.w3.org/2001/XMLSchema" xmlns:beans = "http://www.springframework.org/schema/beans" targetNamespace = "http://gitee.com/schema/link" elementFormDefault = "qualified" > < xsd:import namespace = "http://www.springframework.org/schema/beans" /> < xsd:import namespace = "http://www.springframework.org/schema/tool" /> < xsd:element name = "service" > < xsd:complexType > < xsd:complexContent > < xsd:extension base = "beans:identifiedType" > < xsd:attribute name = "ref" type = "xsd:string" use = "required" > < xsd:annotation > < xsd:documentation > <![CDATA[ 服务接口实现类]]> </ xsd:documentation > </ xsd:annotation > </ xsd:attribute > < xsd:attribute name = "interfaceClass" type = "xsd:string" use = "required" > < xsd:annotation > < xsd:documentation > <![CDATA[服务接口]]> </ xsd:documentation > </ xsd:annotation > </ xsd:attribute > < xsd:attribute name = "version" type = "xsd:string" /> </ xsd:extension > </ xsd:complexContent > </ xsd:complexType > </ xsd:element > </ xsd:schema > |
3. 编写NamespaceHandler
registerBeanDefinitionParser方法的key是xsd配置的element的name,表示service元素由LinkServiceBeanDefinitionParser对象解析
1
2
3
4
5
6
|
public class LinkNamespaceHandler extends NamespaceHandlerSupport { @Override public void init() { this .registerBeanDefinitionParser( "service" , new LinkServiceBeanDefinitionParser()); } } |
4. 编写BeanDefinitionParser
从element中解析出属性,注册到BeanDefinitionBuilder
1
2
3
4
5
6
7
8
9
10
11
12
|
public class LinkServiceBeanDefinitionParser extends AbstractSingleBeanDefinitionParser { @Override protected Class getBeanClass(Element element) { return ServiceConfig. class ; } @Override protected void doParse(Element element, BeanDefinitionBuilder bean) { bean.addPropertyValue( "ref" , element.getAttribute( "ref" )); bean.addPropertyValue( "interfaceClass" , element.getAttribute( "interfaceClass" )); bean.addPropertyValue( "version" , element.getAttribute( "version" )); } } |
5. 配置spring.handlers和spring.schemas
1
2
|
http\://gitee.com/schema/link=com.test.xsd.handler.LinkNamespaceHandler http\://gitee.com/schema/link/link.xsd=META-INF/link.xsd |
6. 配置spring的加载文件
在文件头部需要引入link的schema
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
<? xml version = "1.0" encoding = "UTF-8" ?> < beans xmlns = "http://www.springframework.org/schema/beans" xmlns:link = "http://gitee.com/schema/link" xmlns:xsi = "http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://gitee.com/schema/link http://gitee.com/schema/link/link.xsd"> <!-- rpc服务 --> < link:service id = "serviceConfig" ref = "helloService" interfaceClass = "com.test.service.HelloService" version = "1.0.0" /> </ beans > |
7. 测试
1
2
3
4
5
6
7
|
public class App { public static void main(String[] args) { ApplicationContext context = new ClassPathXmlApplicationContext( "link-server.xml" ); ServiceConfig config = (ServiceConfig) context.getBean( "serviceConfig" ); System.out.println(config.toString()); } } |
Spring Schema扩展机制
1. 概述
Spring2.0开始,Spring提供XML Schema可扩展机制,用户可以自定义XML Schema文件,并自定义
XML Bean解析器,集成到Spring IOC容器中。
2. 步骤
创建一个XML Schema文件,描述自定义的合法构建模块,也就是xsd文件。
自定义处理器类,并实现NamespaceHandler接口。
自定义一个或者多个解析器,实现BeanDefinitionParser接口(关键部分)。
注册上面的组建到Spring IOC容器。
3. 示例如下
(1) 自定义XML Schema文件
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
<? xml version = "1.0" encoding = "UTF-8" ?> < xsd:schema xmlns = "http://www.liuenyuan.com/schema/myns" xmlns:xsd = "http://www.w3.org/2001/XMLSchema" xmlns:beans = "http://www.springframework.org/schema/beans" targetNamespace = "http://www.liuenyuan.com/schema/myns" elementFormDefault = "qualified" > < xsd:import namespace = "http://www.springframework.org/schema/beans" /> < xsd:element name = "dateFormat" > < xsd:complexType > < xsd:complexContent > < xsd:extension base = "beans:identifiedType" > < xsd:attribute name = "pattern" type = "xsd:string" use = "required" /> </ xsd:extension > </ xsd:complexContent > </ xsd:complexType > </ xsd:element > </ xsd:schema > |
自定义targetNamespace是http://www.liuenyuan.com/schema/myns,xmlns与命名空间必须一致。
(2) 自定义NamespaceHandler
NamespaceHandler接口只有三个方法
-
init()
:在NamespaceHandler被使用之前调用,完成初始化 -
parse()
:解析元素 -
decorate()
:嵌套元素时候调用
Spring提供一个默认实现类NamespaceHandlerSupport,注入每个元素的解析器即可。
用到了代理委托概念。NamespaceHandlerSupport可以注册任意个BeanDefinitionParser,负责所有自定义元素编排,实际XML解析工作委托给各个BeanDefinitioParser负责。
(3) 自定义BeanDefinitionParser
BeanDefinitionParser 将被调用,如果NamespapceHandler遇到元素类型已经有对应注册的parser(例如上面的handler如果遇到dateformat,DateformatDefinitionParser会被调用,
解析相应的属性设置到Bean中)将会被调用。BeanDefinitionParser负责解析一个顶级元素。
Spring提供AbstractSingleBeanDefinitionParser处理繁重的解析工作。
-
getBeanClass()
:返回元素Class类型 -
doParse()
:添加元素属性或者构造参数
(4) 注册handler和schema
把实现的NamespaceHandler和xsd文件配置到指定的配置文件中。位于META-INF目录中。
spring.handlers文件包含xml schema uri和Handler类映射关系。
1
2
|
http\://www.liuenyuan.com/schema/myns=\ com.ley.springboot.schema.xml.MynsNamespaceHandler |
遇到http\://www.liuenyuan.com/schema/myns命名空间的时候会交给MynsNamespaceHandler来处理,key部分必须和xsd文件中的targetNamespace值保持一致
spring.schemas文件包含xml schema xsd文件命名空间和文件路径映射关系。
1
|
http\://www.liuenyuan.com/schema/myns.xsd=META-INF/myns.xsd |
(5) 测试
NamespaceHandler实现类
1
2
3
4
5
6
|
public class MynsNamespaceHandler extends NamespaceHandlerSupport { @Override public void init() { registerBeanDefinitionParser( "dateFormat" , new MynsBeanDefinitionParser()); } } |
BeaDefinitionParser实现类
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
import org.springframework.beans.factory.support.BeanDefinitionBuilder; import org.springframework.beans.factory.xml.AbstractSingleBeanDefinitionParser; import org.w3c.dom.Element; import java.text.SimpleDateFormat; public class MynsBeanDefinitionParser extends AbstractSingleBeanDefinitionParser { @Override protected Class<?> getBeanClass(Element element) { return SimpleDateFormat. class ; } @Override protected void doParse(Element element, BeanDefinitionBuilder builder) { String pattern = element.getAttribute( "pattern" ); builder.addConstructorArgValue(pattern); } } |
以上为个人经验,希望能给大家一个参考,也希望大家多多支持服务器之家。
原文链接:https://blog.csdn.net/ghaohao/article/details/81116761