一、前言

Spring 为基于 XML 构建的应用提供了一种扩展机制,用于定义和配置 Bean。 它允许使用者编写自定义的 XML bean 解析器,并将解析器本身以及最终定义的 Bean 集成到 Spring IOC 容器中。

二、自定义 XML Schema 扩展

为了搞懂 Spring 的 XML 扩展机制,最直接的方式便是实现一个自定义的扩展。实现的步骤也为四步:

  1. 编写一个 XML schema 文件描述的你节点元素。
  2. 编写一个 NamespaceHandler 的实现类
  3. 编写一个或者多个 BeanDefinitionParser 的实现 (关键步骤).
  4. 注册上述的 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. 注册 schemahandler

最后一步还需要通知 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扩展机制的更多相关文章

  1. 聊聊 Spring 的 XML Schema 扩展机制的使用方式

    前言 在当前Java生态,Spring算的上是最核心的框架,所有的开发组件想要得到大范围更便捷的使用,都要和Spring进行整合,比如我们熟知的Mybatis.Dubbo等,以及内部封装的各类组件包括 ...

  2. 缘起 Dubbo ,讲讲 Spring XML Schema 扩展机制

    背景 在 Dubbo 中,可以使用 XML 配置相关信息,也可以用来引入服务或者导出服务.配置完成,启动工程,Spring 会读取配置文件,生成注入 相关 Bean.那 Dubbo 如何实现自定义 X ...

  3. 6.2 dubbo在spring中自定义xml标签源码解析

    在6.1 如何在spring中自定义xml标签中我们看到了在spring中自定义xml标签的方式.dubbo也是这样来实现的. 一 META_INF/dubbo.xsd 比较长,只列出<dubb ...

  4. 6.1 如何在spring中自定义xml标签

    dubbo自定义了很多xml标签,例如<dubbo:application>,那么这些自定义标签是怎么与spring结合起来的呢?我们先看一个简单的例子. 一 编写模型类 package ...

  5. Spring中ApplicationContext加载机制和配置初始化

    Spring中ApplicationContext加载机制.        加载器目前有两种选择:ContextLoaderListener和ContextLoaderServlet.        ...

  6. Spring Schema扩展机制

    1:概述 Spring2.0开始,Spring提供XML Schema可扩展机制,用户可以自定义XML Schema文件,并自定义 XML Bean解析器,集成到Spring IOC容器中. 2:步骤 ...

  7. day05 Spring中自定义注解的用处-之获取自定义的Servie

    PS: 在RPC远程调用中,想要获取自定义的service的方法,就得自定义标签遍历拿到方法 PS:在spring中,两个最核心的 概念是aop和ioc,aop其实就是动态代理. ioc 就是解决对象 ...

  8. spring中自定义Event事件的使用和浅析

    在我目前接触的项目中,用到了许多spring相关的技术,框架层面的spring.spring mvc就不说了,细节上的功能也用了不少,如schedule定时任务.Filter过滤器. intercep ...

  9. spring中的事务传播机制

    1.事务的实现思想 在spring中要想某个方法具有事务,只要在方法前加一个@Transactional注解.然后spring就会利用aop思想,在这个方法执行前开启事务, 在方法执行后选择提交事务或 ...

随机推荐

  1. 【曹工杂谈】Maven IOC 容器-- Guice内部有什么

    Google Guice容器内部有什么 前言 Maven系列,好几天没写了,主要是这几天被Google Guice卡住了,本来是可以随便带过Guice,讲讲guice的用法就够了(这个已经讲了,在前面 ...

  2. Java中使用jxl.jar将数据导出为excel文件

      Java对Excel文件的读写操作可由jxl.jar或poi.jar实现,这里使用jxl.jar完成对Excel文件的导出. 一.将Excel文件导出在本地 步骤:   创建文件 -> 创建 ...

  3. 剑指offer计划20( 搜索与回溯算法中等)---java

    1.1.题目1 剑指 Offer 07. 重建二叉树 1.2.解法 注释解法. 1.3.代码 class Solution { int[] preorder; HashMap<Integer, ...

  4. java eclipse 使用随笔

    1,无法import java.awt. 等各种文件,解决办法:(在module-info.java文件中加入requires java,desktop这句话)

  5. windows安装python2.7、python3.7和pycharm

    下载安装包 下载可执行文件 安装 安装2.7 安装pycharm

  6. 你会阅读appium官网文档吗

    高效学习appium第一步,学会查看appium官方文档.如果能把appium文档都通读一遍,对学习appium大有益处. 而能做到通读appium官方文档的人,想必不是很多,刚开始学习appium的 ...

  7. hadoop生态之面试题篇

    一.hdfs的高可用 1.先说下自己的理解, 正常的hdfs有namenode,datanode,secondnamenode,但是second name node 不是真正意义上的namenode备 ...

  8. 鸿蒙内核源码分析(索引节点篇) | 谁是文件系统最重要的概念 | 百篇博客分析OpenHarmony源码 | v64.01

    百篇博客系列篇.本篇为: v64.xx 鸿蒙内核源码分析(索引节点篇) | 谁是文件系统最重要的概念 | 51.c.h.o 文件系统相关篇为: v62.xx 鸿蒙内核源码分析(文件概念篇) | 为什么 ...

  9. 【深度学习】softmax回归——原理、one-hot编码、结构和运算、交叉熵损失

    1. softmax回归是分类问题 回归(Regression)是用于预测某个值为"多少"的问题,如房屋的价格.患者住院的天数等. 分类(Classification)不是问&qu ...

  10. 将Oracle数据库数据每天备份恢复一次数据到另一台服务器上两份数据

    1.创建用户,授权,创建测试数据 创建用户 CREATE USER test identified by 123; 授权 grant dba to test; 创建测试数据 create table ...