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標籤訂義
相關文章
相關標籤/搜索