文档章节

spring-基于可扩展Schema的特性自定义标签

细肉云吞
 细肉云吞
发布于 2017/04/13 10:49
字数 1259
阅读 164
收藏 0

引言

从spring 2.0开始,spring开始支持基于schema的bean的配置和定义,即通过标签定义和配置bean交由spring容器管理,它和通过spring的<bean>标签定义bean是相同的,但对于用户更透明和友好。

例如,需要配置User bean,通过spring提供的bean标签配置如下:

	<bean class="com.github.thinwonton.spring.schema.User">
		<property name="name" value="hugo"></property>
		<property name="age" value="18"></property>
		<property name="addr" value="中国"></property>
		<property name="gender" value="male"></property>
	</bean>

如果gender属性只接受male和female,这在bean标签中是不可控的,但我们通过自定义扩展spring的bean标签后,可以做到属性可控。另外,哪些是必须的,哪些是可选的,这都可以通过自定义标签做到。

<test:user id="userBean" name="hugo" age="18"  addr="中国" gender="male" />

想写自定义标签,但首先需要了解 XML Schema Definition(XSD) ,这里仅对一些遇到的标签说明,其它请各位自学。

http://www.runoob.com/schema/schema-tutorial.html

需求与实现

需求

** 自定义一个自定义标签mytag.xsd,其中一个元素节点为user,元素有四个属性分别是name、age、addr、gender,其中name/age/addr为必须填写的,gender是可选的并且是枚举类型。 **

spring官方文档详细地说明了扩展schema标签的步骤,如果英文好的话可以去看看,不行的话那往下看吧。 http://docs.spring.io/spring/docs/4.2.9.RELEASE/spring-framework-reference/htmlsingle/#extensible-xml-introduction

实现

实现以上需求需要完成以下步骤:

  • 设计配置属性和JavaBean
  • 编写XSD文件,定义标签的属性
  • 编写NamespaceHandler和BeanDefinitionParser完成解析工作
  • 编写spring.handlers和spring.schemas文件,串联起所有部件
  • 在spring Bean配置文件中引用

先看一下完成需求后的工程结构:

输入图片说明

(1)设计配置属性和JavaBean

//User.java
package com.github.thinwonton.spring.schema;

public class User {
	private String name;
	private int age;
	private String addr;
	private String gender;

    //忽略getter/setter

	@Override
	public String toString() {
		return "User [name=" + name + ", age=" + age + ", addr=" + addr + ", gender=" + gender + "]";
	}
}

(2)编写XSD文件,定义标签的属性。xsd文件名:mytag.xsd。

<?xml version="1.0" encoding="UTF-8"?>
<xsd:schema xmlns="http://www.github.com/thinwonton/schema/mytag"
	xmlns:xsd="http://www.w3.org/2001/XMLSchema" 
	xmlns:beans="http://www.springframework.org/schema/beans"
	targetNamespace="http://www.github.com/thinwonton/schema/mytag"
	elementFormDefault="qualified" 
	attributeFormDefault="unqualified">

	<xsd:import namespace="http://www.springframework.org/schema/beans" />

	<!-- xsd:element 表示定义标签 -->
	<xsd:element name="user">
		<xsd:complexType>
			<xsd:complexContent>
				<!-- 继承定义 从namespace="http://www.springframework.org/schema/beans" -->
				<xsd:extension base="beans:identifiedType">
					<!-- 定义name属性,string类型,必须 -->
					<xsd:attribute name="name" type="xsd:string" use="required" />
					<!-- 定义age属性,无符号int类型,必须 -->
					<xsd:attribute name="age" type="xsd:unsignedInt" use="required" />
					<!-- 定义addr属性,string类型,必须 -->
					<xsd:attribute name="addr" type="xsd:string" use="required" />
					<!-- 定义gender属性,枚举类型,默认值是male,可选 -->
					<xsd:attribute name="gender" use="optional" default="male">
						<xsd:simpleType>
							<xsd:restriction base="xsd:string">
								<xsd:enumeration value="male" />
								<xsd:enumeration value="female" />
							</xsd:restriction>
						</xsd:simpleType>
					</xsd:attribute>
				</xsd:extension>
			</xsd:complexContent>
		</xsd:complexType>
	</xsd:element>
</xsd:schema>

说明:

  • xsd:element 表示定义标签
  • xsd:extension 如java中的继承,把现有的定义继承进来
  • xsd:attribute 标签带有的属性
  • xsd:restriction 对标签改属性进一步的限制,进行一些值的约束

(3) 编写NamespaceHandler和BeanDefinitionParser完成解析工作

//UserBeanDefinitionParser.java
public class UserBeanDefinitionParser extends AbstractSingleBeanDefinitionParser {
	@Override
	protected Class<?> getBeanClass(Element element) {
		return User.class;
	}

	@Override
	protected void doParse(Element element, BeanDefinitionBuilder builder) {
		// 获取属性
		String name = element.getAttribute("name");
		int age = Integer.parseInt(element.getAttribute("age"));
		String addr = element.getAttribute("addr");
		String gender = element.getAttribute("gender");

		// 给bean赋值
		builder.addPropertyValue("name", name);
		builder.addPropertyValue("age", age);
		builder.addPropertyValue("addr", addr);
		builder.addPropertyValue("gender", gender);
	}
}
public class MytagNamespaceHandler extends NamespaceHandlerSupport {
	@Override
	public void init() {
         //"user"对应于xsd文件里面的<xsd:element name="user">
        //这里的意思是告诉spring使用UserBeanDefinitionParser解析器解析user这个元素
		registerBeanDefinitionParser("user", new UserBeanDefinitionParser());
	}
}

(4)编写spring.handlers和spring.schemas文件,串联起所有部件

spring.schemas文件,把命令空间与工程中的具体定义文件相关联

 http\://www.github.com/thinwonton/schema/mytag/mytag.xsd=META-INF/mytag.xsd

spring.handlers文件,告诉spring该让哪个命令空间处理器处理xsd定义的一堆元素

http\://www.github.com/thinwonton/schema/mytag=com.github.thinwonton.spring.schema.MytagNamespaceHandler

(5)在spring配置文件中引用

引入schema,把schema的命令空间给一个缩写名mytag

<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
	xmlns:context="http://www.springframework.org/schema/context"
	xmlns:mytag="http://www.github.com/thinwonton/schema/mytag"
	xsi:schemaLocation="http://www.springframework.org/schema/beans        
    http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
    http://www.springframework.org/schema/context 
    http://www.springframework.org/schema/context/spring-context-4.0.xsd
    http://www.github.com/thinwonton/schema/mytag 
    http://www.github.com/thinwonton/schema/mytag/mytag.xsd
    ">

	<mytag:user id="userBean" name="hugo" age="18"  addr="中国" gender="male" />
	
</beans>

这里可能发生命名控件不能识别的问题,这是因为我们的文件没有上传到网络上,这时我们需要在eclipse中指定命令空间的解析地址映射到本地文件中。

输入图片说明

测试:

public class Main {
	public static void main(String[] args) {
		ApplicationContext context = new ClassPathXmlApplicationContext("classpath:spring/spring-context.xml");
		User user = context.getBean(User.class);
		System.out.println(user.toString());
	}
}

相关资料

  • 代码

https://git.oschina.net/thinwonton/spring-showcase.git

项目里的spring-schema-extend工程

  • 具体应用 dubbo标签定义

© 著作权归作者所有

细肉云吞
粉丝 118
博文 224
码字总数 167731
作品 0
其它
高级程序员
私信 提问
Dubbo源码-Dubbo是如何随心所欲自定义XML标签的

叨叨 今天考虑了很久要不要写这篇文章。 距离《Dubbo源码》系列的开篇到现在已经快两个月时间了。当时是想着工作上的RPC框架使用存在一些让人头疼的问题,就来看看Dubbo给出了一套什么样的解...

Jackie_Zheng
2018/05/20
0
0
dubbo “插入”到spring框架

作为一个分布式服务治理框架,dubbo做的非常好,在业界使用很广,所以最近研究了下这个框架。任何框架要研究其原理最好的办法之一就是沿着其运行流 程进行追踪,这样就能从上到下,从粗到细对...

cc-s
2015/10/29
115
0
Java必备干货:Spring框架之IOC的基本配置

Spring框架之IOC的基本配置,前言,上一章我们学习了Spring的IOC特性以及IOC的实现原理:注解和反射,本章我们将学习如何在Spring中使用IOC。 Spring的IOC配置 Spring最重要的特性是IOC控制反...

好程序员IT
07/10
36
0
Spring Security3源码分析-FilterChainProxy初始化

很久没有更新博客了,最近对Spring Security做了比较深入的研究。 spring security的教程网上很多: http://lengyun3566.iteye.com/category/153689 http://wenku.baidu.com/view/b0c0dc0b7...

Dead_knight
2014/01/20
1K
2
零侵入的 RESTful API 文档框架 - HttpDoc

HttpDoc 基于Java标准doc注释构建的代码零侵入的HTTP RESTful API在线阅览文档及测试界面框架 JSON-Editor: httpdoc-ui TextArea: httpdoc-ui-v1 功能特性 基础功能无需为配合HttpDoc框架而多...

不会钓鱼的兔子
2018/11/16
1K
0

没有更多内容

加载失败,请刷新页面

加载更多

OSChina 周一乱弹 —— 年迈渔夫遭黑帮袭抢

Osc乱弹歌单(2019)请戳(这里) 【今日歌曲】 @tom_tdhzz :#今日歌曲推荐# 分享Elvis Presley的单曲《White Christmas》: 《White Christmas》- Elvis Presley 手机党少年们想听歌,请使劲...

小小编辑
今天
2.2K
20
CentOS7.6中安装使用fcitx框架

内容目录 一、为什么要使用fcitx?二、安装fcitx框架三、安装搜狗输入法 一、为什么要使用fcitx? Gnome3桌面自带的输入法框架为ibus,而在使用ibus时会时不时出现卡顿无法输入的现象。 搜狗和...

技术训练营
昨天
13
0
《Designing.Data-Intensive.Applications》笔记 四

第九章 一致性与共识 分布式系统最重要的的抽象之一是共识(consensus):让所有的节点对某件事达成一致。 最终一致性(eventual consistency)只提供较弱的保证,需要探索更高的一致性保证(stro...

丰田破产标志
昨天
14
0
docker 使用mysql

1, 进入容器 比如 myslq1 里面进行操作 docker exec -it mysql1 /bin/bash 2. 退出 容器 交互: exit 3. mysql 启动在容器里面,并且 可以本地连接mysql docker run --name mysql1 --env MY...

之渊
昨天
19
0
python数据结构

1、字符串及其方法(案例来自Python-100-Days) def main(): str1 = 'hello, world!' # 通过len函数计算字符串的长度 print(len(str1)) # 13 # 获得字符串首字母大写的...

huijue
昨天
7
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部