在spring中存在默认标签与自定义标签两种,例如:<bean/>为默认标签,<tx:annotation-driven/>为自定义标签。spring自定义标签比较灵活,可以扩展自定义标签。

扩展spring自定义标签主要步骤:

  1. 创建一个需要扩展的组件;

  2. 定义一个XSD文件描述组件内容;

  3. 创建一个类,该类实现BeanDifinitionParser接口,主要用来解析XSD文件中的定义和组件的定义;

  4. 创建一个NamespaceHandler类,该类扩展NamespaceHandlerSupport,主要作用是将组件注册到spring的容器中;

  5. 编写spring.handlers和spring.schemas文件


现在用一个简单的实例来说明自定义标签的过程,该实例主要是通过自定义标签来获取对象。

(1)创建一个普通POJO类,该类主要是用来接收配置文件属性。

public class User {
       private String username;
       private String email;
       public String getUsername() {
	     return username;
	}
       public void setUsername(String username) {
	     this.username = username;
	}
	public String getEmail() {
	      return email;
	}
	public void setEmail(String email) {
	      this.email = email;
	}
}


(2)定义一个XSD文件描述组件内容,下面文件中targetNamespace表示文档中要定义的元素来自什么命名空间,elementFormDefault="qualified"表示要求xml文档的每一个元素都要有命名空间指定。该文件主要是定义一个user元素,该元素包含有id,username,email属性,其中属性类型为string。

<?xml version="1.0" encoding="UTF-8"?>
<xsd:schema xmlns="http://www.lw.com/schema/user"
        xmlns:xsd="http://www.w3.org/2001/XMLSchema"
        targetNamespace="http://www.lw.com/schema/user"
        elementFormDefault="qualified" attributeFormDefault="unqualified">
    <xsd:element name="user">
        <xsd:complexType>
            <xsd:attribute name="id" type="xsd:string"></xsd:attribute>
            <xsd:attribute name="username" type="xsd:string"></xsd:attribute>
            <xsd:attribute name="email" type="xsd:string"></xsd:attribute>
        </xsd:complexType>
    </xsd:element>
</xsd:schema>


(3)创建一个UserBeanDifinitionParser类,该类实现BeanDifinitionParser接口,这个类主要用来解析XSD文件中定义元素

package com.lw.spring;

import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.xml.AbstractSingleBeanDefinitionParser;
import org.springframework.util.StringUtils;
import org.w3c.dom.Element;

public class UserBeanDefinitionParser extends
		AbstractSingleBeanDefinitionParser {
	//Element对应的类
	protected Class getBeanClass(Element element) {		
		return User.class;
	}
	//从Element中解析并提取对应的元素
	@Override
	protected void doParse(Element element, BeanDefinitionBuilder builder) {
		String username=element.getAttribute("username");
		String email=element.getAttribute("email");
		//将提取的数据放到BeanDefinitionBuilder中,待到完成所有bean的解析后统一注册到beanFactory中
		if(StringUtils.hasText(username)){
			builder.addPropertyValue("username", username);
		}
		if(StringUtils.hasText(email)){
			builder.addPropertyValue("email", email);
		}
	}

}


(4)创建一个MyNamespaceHandler类,该类扩展NamespaceHandlerSupport,主要是将组件注册到Spring容器中。

package com.lw.spring;

import org.springframework.beans.factory.xml.NamespaceHandlerSupport;


public class MyNamespaceHandler extends NamespaceHandlerSupport {

	@Override
	public void init() {
		registerBeanDefinitionParser("user", new UserBeanDefinitionParser());		
	}	
}


(5)编写spring.handlers和spring.schemas文件,默认位置在工程的/META-INF/文件夹下,需要说明的是在测试过程中创建的META-INF文件夹必须放在classpath路径下,不然就会出现抛出错误,如果你使用的是eclipse创建的工程,可以在src在创建META-INF文件夹,并将spring.handlers和spring.schemas文件放入到该文件下。

spring.handlers该文件存放的是键值对,等号左边表示自定标签的命名空间,等号右边表示自定义处理器的类全名,主要是通过放射来获取该处理器实例对象。

http\://www.lw.com/schema/user=com.lw.spring.MyNamespaceHandler


spring.schemas该文件存放的也是键值对,等号左边表示自定义标签XSD的URL,等号右边表示自定义标签XSD在工程中的具体位置

http\://www.lw.com/schema/user.xsd=com/lw/spring/user.xsd


(6)创建配置文件,在配置文件中引入对应的命名空间及XSD后,就可以直接使用自定义标签。

<?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:user="http://www.lw.com/schema/user"
	xsi:schemaLocation="http://www.springframework.org/schema/beans
	 http://www.springframework.org/schema/beans/spring-beans-3.0.xsd 
	 http://www.lw.com/schema/user 
	 http://www.lw.com/schema/user.xsd">	
	<user:user id="testuser" email="dad" username="ddd"></user:user>	
</beans>


(7)建立一个测试类

package com.lw.spring;

import org.springframework.core.io.Resource;

public class TestSpring {
	public static void main(String[] args) {

		Resource resource=new ClassPathResource("applicationContext.xml");
		XmlBeanFactory factory=new XmlBeanFactory(resource);
		User mytest=(User) factory.getBean("testuser");
		System.out.println(mytest.getUsername()+" , "+mytest.getEmail());

	}

}

运行结果为:

ddd , dad

    以上就是通过简单实例说明扩展Spring自定义标签的过程,若想了解更加自定义标签解析的详细内容,可以参考《Spring源码深度解析》这本书。