一、前言

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 IntelliJ之Spring Cloud直播商城 b2b2c电子商务技术总结

    Maven IntelliJ IntelliJ IDEA 已经内建了对 Maven 的支持.我们在此例中使用的是 IntelliJ IDEA 社区版 11.1. IntelliJ IDEA 的一些特性 ...

  2. Java学习笔记--面对对象OOP

    面向对象编程 OOP 面向对象&面向过程 面向对象编程的本质:以类的方式组织代码,以对象的方法组织数据 面向对象编程的三大特征: 封装 继承 多态 方法 静态方法 通过 static 关键词说 ...

  3. Docker入门系列之一:什么是Docker?

    原文作者:Jeff Hale 原文地址:https://towardsdatascience.com/learn-enough-docker-to-be-useful-b7ba70caeb4b 翻译: ...

  4. linux centos windows服务器修改数据库最大连接数的方法

    1.可查询数据库最大连接数 show variables like '%max_connections%'; 2.修改数据库最大连接数,最大限制上限为16384. 找到数据库配置文件my.cnf,在配 ...

  5. C# Redis学习系列二:Redis基本设置

    上一篇:C# Redis学习系列一:Redis的认识.下载.安装.使用 一.redis 设置密码 使用下载好的 redis-cli.exe 指令: 1.设置密码: config set require ...

  6. gin 源码阅读(1) - gin 与 net/http 的关系

    gin 是目前 Go 里面使用最广泛的框架之一了,弄清楚 gin 框架的原理,有助于我们更好的使用 gin. 这个系列 gin 源码阅读会逐步讲明白 gin 的原理. gin 概览 想弄清楚 gin, ...

  7. 配置阿里云maven

    在安装好Maven之后,默认的~/.m2目录下是没有maven仓库配置文件settings.xml的,默认使用的是官方的仓库,访问速度会非常慢,我们需要配置下国内的仓库. 创建~/.m2/settin ...

  8. python实现rtsp取流并截图

    import cv2 def get_img_from_camera_net(folder_path): cap = cv2.VideoCapture("rtsp://admin:admin ...

  9. [转载]SELinux安全系统基础

    链接:http://www.cnblogs.com/xiaoluo501395377/archive/2013/05/26/3100444.html 本篇随笔将记录一下学习SELinux的一些心得与体 ...

  10. 低差异序列 (low-discrepancy sequences)之Hammerysley在半球中采样点方法的介绍

    半球上的Hammersley 源作者:Holger Dammertz 一组关于如何在2D中使用Hammersley点集以在着色器程序中快速实用地生成半球方向的笔记.如果你发现任何错误或有意见,不要犹豫 ...