Spring中自定义Schema扩展机制
一、前言
Spring 为基于 XML 构建的应用提供了一种扩展机制,用于定义和配置 Bean。 它允许使用者编写自定义的 XML bean 解析器,并将解析器本身以及最终定义的 Bean 集成到 Spring IOC 容器中。
二、自定义 XML Schema 扩展
为了搞懂 Spring 的 XML 扩展机制,最直接的方式便是实现一个自定义的扩展。实现的步骤也为四步:
- 编写一个 XML schema 文件描述的你节点元素。
- 编写一个 NamespaceHandler 的实现类
- 编写一个或者多个 BeanDefinitionParser 的实现 (关键步骤).
- 注册上述的 schema 和 handler
1. 编写 resources/META-INF/Car.xsd
1 <?xml version="1.0" encoding="UTF-8"?>
2 <xsd:schema xmlns="http://www.mycompany.com/schema/my"
3 xmlns:xsd="http://www.w3.org/2001/XMLSchema"
4 xmlns:beans="http://www.springframework.org/schema/beans"
5 targetNamespace="http://www.mycompany.com/schema/my1"
6 elementFormDefault="qualified"
7 attributeFormDefault="unqualified">
8
9 <xsd:import namespace="http://www.springframework.org/schema/beans"/>
10
11 <xsd:element name="car">
12 <xsd:complexType>
13 <xsd:complexContent>
14 <xsd:extension base="beans:identifiedType">
15 <xsd:attribute name="brand" type="xsd:string" use="required"/>
16 <xsd:attribute name="engine" type="xsd:float"/>
17 <xsd:attribute name="horsePower" type="xsd:int"/>
18 </xsd:extension>
19 </xsd:complexContent>
20 </xsd:complexType>
21 </xsd:element>
22 </xsd:schema>
这里,targetNamespace对Car标签很重要,比如说注册一个bean
1 <my1:car id="magic" brand="Magic" engine="4.5" horsePower="605" />
2. 编写 CarNamespaceHandler
1 public class CarNamespaceHandler extends NamespaceHandlerSupport {
2
3 @Override
4 public void init() {
5 //遇到car元素的时候交给CarBeanDefinitionParser来解析
6 registerBeanDefinitionParser("car", new CarBeanDefinitionParser());
7
8 }
9
10 }
编写的NamespaceHandler 来帮助 Spring 解析 XML 中不同命名空间的各类元素。不同的命名空间需要不同的 NamespaceHandler 来处理。使用 CarNamespaceHandler 来解析 car 的命名空间。
1 public interface NamespaceHandler {
2 void init();
3 BeanDefinition parse(Element element, ParserContext parserContext);
4 BeanDefinitionHolder decorate(Node source, BeanDefinitionHolder definition, ParserContext parserContext);
5 }
CarNamespaceHandler 继承 NamespaceHandlerSupport 抽象类,NamespaceHandlerSupport 抽象类实现了 NamespaceHandler 接口,并实现了parse()和decorate()方法,在CarNamespaceHandler 类中实现 NamespaceHandler 接口的init()方法,注册 BeanDefinitionParser 来完成解析节点以及注册 Bean 的工作。
3. 编写 CarBeanDefinitionParser
BeanDefinitionParser 是最为关键的一环。每一个 BeanDefinitionParser 实现类都负责一个映射,将一个 XML 节点解析成 IOC 容器中的一个实体类。
1 public class CarBeanDefinitionParser extends AbstractSingleBeanDefinitionParser {
2
3 @Override
4 protected Class<?> getBeanClass(Element element) {
5 //car元素对应Car对象类型
6 return Car.class;
7 }
8
9 @Override
10 protected void doParse(Element element, BeanDefinitionBuilder builder) {
11
12 String brand = element.getAttribute("brand");
13 String engine = element.getAttribute("engine");
14 String hp = element.getAttribute("horsePower");
15
16 //把对应的属性设置到bean中
17 if(StringUtils.hasText(brand))
18 builder.addPropertyValue("brand", brand);
19
20 if(StringUtils.hasText(engine))
21 builder.addPropertyValue("engine", engine);
22
23 if(StringUtils.hasText(hp))
24 builder.addPropertyValue("horsePower", hp);
25
26 }
27 }
parse() 方法会解析一个个 XML 中的元素,使用 RootBeanDefinition 组装成对象,并最终通过 parserContext 注册到 IOC 容器中。
至此,我们便完成了 XML 文件中定义的对象到 IOC 容器的映射。
4. 注册 schema 和 handler
最后一步还需要通知 Spring,告知其自定义 schema 的所在之处以及对应的处理器。
resources/META-INF/spring.handlers
1 http\://www.mycompany.com/schema/my1=spring.xml.ext.schema.CarNamespaceHandler
resources/META-INF/spring.schemas
1 http\://www.mycompany.com/schema/my1.xsd=META-INF/car.xsd
一个自定义的 XML schema 便扩展完成了,接下来验证一下自定义Schema扩展。
三、验证扩展
定义好Spring的bean配置文件
1 <?xml version="1.0" encoding="UTF-8"?>
2 <beans xmlns="http://www.springframework.org/schema/beans"
3 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
4 xmlns:my1="http://www.mycompany.com/schema/my1"
5 xsi:schemaLocation="
6 http://www.springframework.org/schema/beans
7 http://www.springframework.org/schema/beans/spring-beans.xsd
8 http://www.mycompany.com/schema/my1
9 http://www.mycompany.com/schema/my1.xsd">
10
11 <my1:car id="magic" brand="Magic" engine="4.5" horsePower="605" />
12
13 </beans>
编写测试方法
1 @RunWith(SpringJUnit4ClassRunner.class)
2 @ContextConfiguration(locations = { "classpath:app.xml" })
3 public class SchemaTest {
4
5 @Autowired
6 @Qualifier("magic")
7 private Car car;
8
9 @Test
10 public void propertyTest() {
11 assertNotNull(car);
12
13 String brand = car.getBrand();
14 float engine = car.getEngine();
15 int horsePower = car.getHorsePower();
16
17 System.out.println("==============================");
18 assertEquals("Brand incorrect.Should be Magic.", "Magic", brand);
19 assertEquals("Engine incorrect.Should be 4.5L.", 4.5, engine, 0.000001);
20 assertEquals("HorsePower incorrect.Should be 605hp.", 605, horsePower);
21
22 }
23 }
控制台输出无异常,断言成功。

Spring中自定义Schema扩展机制的更多相关文章
- 聊聊 Spring 的 XML Schema 扩展机制的使用方式
前言 在当前Java生态,Spring算的上是最核心的框架,所有的开发组件想要得到大范围更便捷的使用,都要和Spring进行整合,比如我们熟知的Mybatis.Dubbo等,以及内部封装的各类组件包括 ...
- 缘起 Dubbo ,讲讲 Spring XML Schema 扩展机制
背景 在 Dubbo 中,可以使用 XML 配置相关信息,也可以用来引入服务或者导出服务.配置完成,启动工程,Spring 会读取配置文件,生成注入 相关 Bean.那 Dubbo 如何实现自定义 X ...
- 6.2 dubbo在spring中自定义xml标签源码解析
在6.1 如何在spring中自定义xml标签中我们看到了在spring中自定义xml标签的方式.dubbo也是这样来实现的. 一 META_INF/dubbo.xsd 比较长,只列出<dubb ...
- 6.1 如何在spring中自定义xml标签
dubbo自定义了很多xml标签,例如<dubbo:application>,那么这些自定义标签是怎么与spring结合起来的呢?我们先看一个简单的例子. 一 编写模型类 package ...
- Spring中ApplicationContext加载机制和配置初始化
Spring中ApplicationContext加载机制. 加载器目前有两种选择:ContextLoaderListener和ContextLoaderServlet. ...
- Spring Schema扩展机制
1:概述 Spring2.0开始,Spring提供XML Schema可扩展机制,用户可以自定义XML Schema文件,并自定义 XML Bean解析器,集成到Spring IOC容器中. 2:步骤 ...
- day05 Spring中自定义注解的用处-之获取自定义的Servie
PS: 在RPC远程调用中,想要获取自定义的service的方法,就得自定义标签遍历拿到方法 PS:在spring中,两个最核心的 概念是aop和ioc,aop其实就是动态代理. ioc 就是解决对象 ...
- spring中自定义Event事件的使用和浅析
在我目前接触的项目中,用到了许多spring相关的技术,框架层面的spring.spring mvc就不说了,细节上的功能也用了不少,如schedule定时任务.Filter过滤器. intercep ...
- spring中的事务传播机制
1.事务的实现思想 在spring中要想某个方法具有事务,只要在方法前加一个@Transactional注解.然后spring就会利用aop思想,在这个方法执行前开启事务, 在方法执行后选择提交事务或 ...
随机推荐
- js不同地图坐标系经纬度转换(天地图,高德地图,百度地图,腾讯地图)
1.js转换代码 1 //转换常数 2 var x_pi = 3.14159265358979324 * 3000.0 / 180.0; 3 var pi = 3.14159265358979324; ...
- go中语句为什么不用加分号;结束
不用人加 编译的时候自动加了分号; 编译器工作原理 首先,在一行中,寻找成对的符号,比如一对字符串的引号.一对圆括号,一对大括号 上述任务完成后,在一行中没有其他成对的标示,然后就在行尾追加分号; 所 ...
- Redis核心原理与实践--列表实现原理之quicklist结构
在上一篇文章<Redis列表实现原理之ziplist结构>,我们分析了ziplist结构如何使用一块完整的内存存储列表数据. 同时也提出了一个问题:如果链表很长,ziplist中每次插入或 ...
- Orchard Core Framework Samples
解决方案包含内容 多租户应用 一个ASP.NET Core MVC应用程序,它引用模块项目,并为两个启用了不同模块的租户提供支持. 此Web应用程序的主页提供了更多信息,并链接到两个租户和模块端点.租 ...
- Java基础系列(17)- 顺序结构
顺序结构 JAVA的基本结构就是顺序结构,除非特别说明,否则就按照顺序一句一句执行 顺序结构是最简单的算法结构 语句与语句之间,框与框之间是按从上到下的顺序进行的,它是由若干个依次执行的处理步骤组成的 ...
- SonarQube汉化
SonarQube安装后默认是英文,如果不习惯看英文,可以进行汉化,官方提供了汉化插件. 登录后,汉化步骤如下: 需要点击了解风险,不然查询到插件后没有install按钮 搜索Chinese,找到插件 ...
- python之jsonpath
json 官方文档:http://docs.python.org/library/json.html JSON(JavaScript Object Notation) 是一种轻量级的数据交换格式,它使 ...
- django 常用教程网址
第一:url中反向解析教程网址 https://docs.djangoproject.com/zh-hans/2.2/ref/templates/builtins/#url
- django 如何在HMTL中使用媒体media_url
django 如何在HMTL中使用媒体media_url中指定的路径 第一种: 一. setting.py里,一般图片或者文件上传路径都是是以下设置, MEDIA_URL = '/media/' ...
- 鸿蒙内核源码分析(重定位篇) | 与国际接轨的对外部发言人 | 百篇博客分析OpenHarmony源码 | v55.01
百篇博客系列篇.本篇为: v55.xx 鸿蒙内核源码分析(重定位篇) | 与国际接轨的对外部发言人 | 51.c.h.o 加载运行相关篇为: v51.xx 鸿蒙内核源码分析(ELF格式篇) | 应用程 ...