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

引言

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

例如,须要配置User bean,经过spring提供的bean标签配置以下:java

<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标签后,能够作到属性可控。另外,哪些是必须的,哪些是可选的,这均可以经过自定义标签作到。git

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

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

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

需求与实现

需求

** 自定义一个自定义标签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-introductioneclipse

实现

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

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

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

输入图片说明

(1)设计配置属性和JavaBeanui

//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标签订义
相关文章
相关标签/搜索