聊聊 Spring 的 XML Schema 扩展机制的使用方式
前言
在当前Java生态,Spring算的上是最核心的框架,所有的开发组件想要得到大范围更便捷的使用,都要和Spring进行整合,比如我们熟知的Mybatis、Dubbo等,以及内部封装的各类组件包括Redis、MQ、配置中心等。
有了整合这一步,我们只需引入相应的jar,比如mybatis-spring,然后进行简单的配置后即可在Spring工程中使用Mybatis的功能,也正是由于这样的便捷性,导致很多时候我们没有对其进行深究。
所谓整合,即在Spring的框架下进行扩展,让框架能无缝的与Spring工程配合使用。Spring设计了良好的扩展的机制,本文将对Spring的扩展方法及原理进行简单介绍。
XML Schema扩展
打开mybatis-spring、dubbo的源码会发现在META-INF目录下有两个文件(如下图所示),spring.handlers与spring.schemas,这两个文件就是XML Schema扩展的关键入口点。

XSD
XSD,XML Schema Definition,XML定义。
XML Schema定义XML文档的结构,XML Schema语言也称为XML定义,即XSD。
XSD的语法及使用比较简单,可参考https://www.w3school.com.cn/schema/index.asp进行了解熟悉。
简单的说,XSD用于制定xml文件规范,包括xml中的元素(简单元素、复杂元素)、属性、以及属性类型及约束等。
Spring XML Schema扩展的第一步就是要定义一个xsd文件,比如spring-beans对应xsd文件为http://www.springframework.org/schema/beans/spring-beans.xsd,如下图:


为了简单介绍Spring XML Schema扩展实现,下面将一个简单例子(模拟一个简单的分布式id生成器,不会实现具体功能)进行说明,xsd定义如下(文件命名为DistributedId.xsd,在META-INF目录下):
<?xml version="1.0" encoding="UTF-8"?>
<xsd:schema xmlns="http://www.hexup.com/schema/distributed-id"
xmlns:xsd="http://www.w3.org/2001/XMLSchema" targetNamespace="http://www.hexup.com/schema/distributed-id">
<xsd:element name="distributed-id">
<xsd:complexType>
<xsd:attribute name="id" type="xsd:string"></xsd:attribute>
<xsd:attribute name="bizCode" type="xsd:string"></xsd:attribute>
<xsd:attribute name="length" type="xsd:int"></xsd:attribute>
</xsd:complexType>
</xsd:element>
</xsd:schema>
上述xsd文件里定义了一个复杂元素distributed-id,包含属性id,bizCode,length,形如:
<distributed-id id="xxx" bizCode="xxx" length="xxx"></distributed-id>
注意:xmlns,即为xml namespace,xml命名空间,后面跟的http链接地址可以不存在,因为xsd会放在当前工程的META-INF下。
配置spring.handlers和spring.schemas
如下两张图所示,spring.schemas文件中用于说明xsd的文件路径,spring.schemas文件用于说明解析此类xsd定义的标签的处理类,下面会对处理类进行详细说明。


NameSpaceHandler与BeanDefinitionParser
定义类DistributedIdNamespaceHandler继承NamespaceHandlerSupport,init方法用于注册BeanDefinition解析器,也就是解析xml中对应标签为Spring Bean。
public class DistributedIdNamespaceHandler extends NamespaceHandlerSupport {
@Override
public void init() {
registerBeanDefinitionParser("distributed-id", new DistributedIdParser());
}
}
同时要创建BeanDefinitionParser
public class DistributedIdParser implements BeanDefinitionParser {
@Override
public BeanDefinition parse(Element element, ParserContext parserContext) {
// 解析xml内的标签
String bizCode = element.getAttribute("bizCode");
int length = Integer.valueOf(element.getAttribute("length"));
String id = element.getAttribute("id");
// 创建DistributedIdFactoryBean bean
BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition();
builder.getRawBeanDefinition().setBeanClass(DistributedIdFactoryBean.class);
builder.setScope(BeanDefinition.SCOPE_SINGLETON);
builder.addPropertyValue("bizCode", bizCode);
builder.addPropertyValue("length", length);
BeanDefinition beanDefinition = builder.getBeanDefinition();
parserContext.getRegistry().registerBeanDefinition(id, beanDefinition);
return beanDefinition;
}
}
其中DistributedIdFactoryBean实现FactoryBean接口用于创建DistributedIdComponent Bean,如下
public class DistributedIdFactoryBean implements InitializingBean, FactoryBean<DistributedIdComponent> {
private String bizCode;
private int length;
private DistributedIdComponent distributedIdComponent;
@Override
public DistributedIdComponent getObject() throws Exception {
return distributedIdComponent;
}
@Override
public Class<?> getObjectType() {
return DistributedIdComponent.class;
}
@Override
public boolean isSingleton() {
return false;
}
@Override
public void afterPropertiesSet() throws Exception {
distributedIdComponent = new DistributedIdComponent(bizCode, length);
}
public void setBizCode(String bizCode) {
this.bizCode = bizCode;
}
public void setLength(int length) {
this.length = length;
}
}
目标Bean DistributedIdComponent如下:
public class DistributedIdComponent {
private String bizCode;
private int length;
public DistributedIdComponent() {
}
public DistributedIdComponent(String bizCode, int length) {
this.bizCode = bizCode;
this.length = length;
}
public String generateId() {
System.out.println("mock generate id");
return String.valueOf(System.currentTimeMillis()).substring(0, length);
}
public String getBizCode() {
return bizCode;
}
public void setBizCode(String bizCode) {
this.bizCode = bizCode;
}
public int getLength() {
return length;
}
public void setLength(int length) {
this.length = length;
}
}
使用
spring配置文件,spring-service.xml中配置distributed-id标签以及对应的属性值,如下:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:distributed-id="http://www.hexup.com/schema/distributed-id"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd http://www.hexup.com/schema/distributed-id http://www.hexup.com/schema/distributed-id.xsd">
<distributed-id:distributed-id id="test" bizCode="test" length="8"></distributed-id:distributed-id>
</beans>
运行容器验证:
public class App {
public static void main(String[] args) {
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("spring-service.xml");
DistributedIdComponent bean = context.getBean(DistributedIdComponent.class);
String id = bean.generateId();
System.out.println("id:" + id);
}
}
总结
本文主要介绍了Spring XML Schema扩展机制的使用方法,大致步骤为定义XSD文件、配置spring.schemas、编码实现NameSpaceHanlder和BeanDefinitionParser实现类、配置spring.handlers。但未说明具体的实现原理,后续会有一篇文章详细介绍Spring源码是怎么实现扩展的,以及介绍为什么使用FactoryBean来创建具体的Bean等问题。
聊聊 Spring 的 XML Schema 扩展机制的使用方式的更多相关文章
- 缘起 Dubbo ,讲讲 Spring XML Schema 扩展机制
背景 在 Dubbo 中,可以使用 XML 配置相关信息,也可以用来引入服务或者导出服务.配置完成,启动工程,Spring 会读取配置文件,生成注入 相关 Bean.那 Dubbo 如何实现自定义 X ...
- Spring中自定义Schema扩展机制
一.前言 Spring 为基于 XML 构建的应用提供了一种扩展机制,用于定义和配置 Bean. 它允许使用者编写自定义的 XML bean 解析器,并将解析器本身以及最终定义的 Bean 集成到 S ...
- Spring Schema扩展机制
1:概述 Spring2.0开始,Spring提供XML Schema可扩展机制,用户可以自定义XML Schema文件,并自定义 XML Bean解析器,集成到Spring IOC容器中. 2:步骤 ...
- dubbo源码之一——xml schema扩展
dubbo源码版本:2.5.4 dubbo-parent |----dubbo-config |----dubbo-config-api |----com.alibaba.dubbo.config.* ...
- Spring基于xml注入bean的几种方式?
(1)Set方法注入: (2)构造器注入:①通过index设置参数的位置:②通过type设置参数类型: (3)静态工厂注入: (4)实例工厂:
- 聊聊spring的那些扩展机制
1.背景 慎入:本文将会有大量代码出入. 在看一些框架源码的时候,可以看见他们很多都会和Spring去做结合.举个例子dubbo的配置: 很多人其实配置了也就配置了,没有去过多的思考:为什么这么配置s ...
- Spring 的微内核与FactoryBean扩展机制--转载
作者:江南白衣 原文地址: http://www.blogjava.net/calvin/archive/2005/08/30/11099.html http://www.blogjava.net/c ...
- Spring的Xml和JavaConfig 扩展你选哪一个?
引言 上一篇文章我们有怎么介绍到如何通过XML的形式来定义Spring的扩展<Spring面试高频题如何:自定义XML schema 扩展>,好多人都在吐槽现在都什么年代了,xml还有人再 ...
- Spring可扩展的XML Schema机制
可扩展的XML Schema机制 从Spring2.0开始,Spring提供了XML Schema可扩展机制,用户可以自定义XML Schema文件,并自定义XML Bean解析器,并集成到Sprin ...
随机推荐
- 一.文件处理和json模块(容易混淆知识点即用法)
一.文件处理 注意点1: 打开文件包含两部分资源:操作系统级打开得文件+应用程序的变量. 在操作完毕一个文件时,必须把该文件的两部分资源一个不落的回收 如下: f.close() #回收操作系统级打开 ...
- Kernighan《UNIX 传奇:历史与回忆》杂感
Brian W. Kernighan 是一个伟大的技术作家,我买了他写的几乎所有书.他近些年的书我买的是 Kindle 电子版,不占地方. 以下是我手上保存的纸版书: Kernighan 的书大多与别 ...
- python正则表达式基本语法
一.最常用的匹配语法 re.match 从头开始匹配 re.search 匹配包含 re.findall 把所有匹配到的字符放到以列表中的元素返回 re.split 以匹配到的字符当做列表分隔符 r ...
- Python中数据类型的转换
bytes<-->str a="hello" #str字符型 #str转换为bytes类型 b=a.encode("utf-8") 或 b=byte ...
- UVA11384正整数序列(把123..变成0的最小步数)
题意: 给定一个正整数n,你的任务是最少的操作次数把序列1 2 3 4 5...n中所有的数字都变成0,每次操作可以从序列中选择一个活多个整数,同时减去一个相同的正整数,比如 1 2 3可以 ...
- spring源码解析之属性编辑器propertyEditor
异常信息造成此异常的原因bean配置文件调用代码特别说明:异常解决注册springt自带的属性编辑器 CustomDateEditor控制台输出属性编辑器是何时并如何被注册到spring容器中的?查看 ...
- maven简单入门
maven简单部署webapp项目流程及注意事项 maven了解 简介: Maven 是一个项目管理工具,它包含了一个项目对象模型 (POM: Project Object Model),一组标准集合 ...
- SE_Work2_交点个数
项目 内容 课程:北航-2020-春-软件工程 博客园班级博客 要求:求交点个数 个人项目作业 班级:005 Sample GitHub地址 IntersectProject 一.PSP估算 在开始实 ...
- 【BUAA软工】第一次团队作业——团队介绍
项目 内容 班级:北航2020春软件工程 博客园班级博客 作业:团队介绍与采访往届团队 团队作业-团队介绍和采访 Part I 团队成员介绍 有图有真(jia)相 大名 个人介绍 角色意向 李PX 来 ...
- Go - 开箱即用,WEB 界面一键安装,没有项目经验,可以拿这个练手
安装界面 启动程序之后,会在浏览器中自动打开安装界面. 因为程序会使用到 Redis 和 MySQL,所以安装前请输入 Redis.MySQL 配置信息,点击初始化按钮,会将用到的数据表和默认数据进行 ...