基础知识:
Spring默认会将xml中所有等标签解析为BeanDefinition的抽象,自定义标签的本质是扩展Spring自身的标签,使其从自定义标签转化为BeanDefinition的过程。
自定标签创建过程:
1.创建映射标签实体JavaBean: Person/User
package com.zhiwei.basic.tag;
import java.util.List;
public class Person {
private String personName;
private Integer age;
private List<String> nickName;
public String getPersonName() {
return personName;
}
public void setPersonName(String personName) {
this.personName = personName;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
public List<String> getNickName() {
return nickName;
}
public void setNickName(List<String> nickName) {
this.nickName = nickName;
}
@Override
public String toString() {
return "Person [name=" + personName + ", age=" + age + ", nickName=" + nickName + "]";
}
}
package com.zhiwei.basic.tag;
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;
}
@Override
public String toString() {
return "User [userName=" + userName + ", email=" + email + "]";
}
}
2.创建标签解析器
package com.zhiwei.basic.tag;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.xml.AbstractSingleBeanDefinitionParser;
import org.springframework.util.StringUtils;
import org.w3c.dom.Element;
/**
* XML中的Bean标签解析器:将<dubbo:user>解析为User对象
*
*/
public class UserBeanDefinitionParser extends AbstractSingleBeanDefinitionParser {
@Override
protected Class<User> getBeanClass(Element element) {
return User.class;
}
@Override
protected void doParse(Element element, BeanDefinitionBuilder bean) {
String userName = element.getAttribute("userName");
String email = element.getAttribute("email");
if (StringUtils.hasText(userName)) {
bean.addPropertyValue("userName", userName);
}
if (StringUtils.hasText(email)) {
bean.addPropertyValue("email", email);
}
}
}
package com.zhiwei.basic.tag;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.xml.AbstractSingleBeanDefinitionParser;
import org.springframework.util.StringUtils;
import org.w3c.dom.Element;
/**
* XML中的Bean标签解析器:将<dubbo:user>解析为User对象
*
*/
public class PersonBeanDefinitionParser extends AbstractSingleBeanDefinitionParser {
protected Class<Person> getBeanClass(Element element) {
return Person.class;
}
protected void doParse(Element element, BeanDefinitionBuilder bean) {
String userName = element.getAttribute("personName");
String email = element.getAttribute("age");
String nickName = element.getAttribute("nickName");
if (StringUtils.hasText(userName)) {
bean.addPropertyValue("personName", userName);
}
if (StringUtils.hasText(email)) {
bean.addPropertyValue("age", email);
}
if (StringUtils.hasText(nickName)) {
bean.addPropertyValue("nickName", nickName);
}
}
}
3.创建命名空间处理器:NamespaceHandler
package com.zhiwei.basic.tag;
import org.springframework.beans.factory.xml.NamespaceHandlerSupport;
/**
* 命名空间处理器:
*/
public class NamespaceHandler extends NamespaceHandlerSupport {
/**
* DefaultBeanDefinitionDocumentReader调用
* 调用时间:自定义元素定义之后,自定义元素真正被解析之前
*/
@Override
public void init() {
registerBeanDefinitionParser("user", new UserBeanDefinitionParser());
registerBeanDefinitionParser("person", new PersonBeanDefinitionParser());
}
}
4.创建自定义标签的XML约束文件:XSD
<?xml version="1.0" encoding="UTF-8"?>
<xsd:schema xmlns="http://www.zhiwei.com/schema/user"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
targetNamespace="http://www.zhiwei.com/schema/user"
elementFormDefault="qualified"
attributeFormDefault="unqualified">
<!-- 定义标签元素及其类型 -->
<xsd:element name="user" type="user" />
<!-- 定义标签元素的类型 -->
<xsd:complexType name="user">
<xsd:attribute name="id" type="xsd:string" />
<xsd:attribute name="userName" type="xsd:string" default="zhangsan"/>
<xsd:attribute name="email" type="xsd:string" />
</xsd:complexType>
<xsd:element name="person" type="person" />
<xsd:complexType name="person">
<xsd:attribute name="id" type="xsd:string" />
<xsd:attribute name="personName" type="xsd:string"/>
<xsd:attribute name="age" type="xsd:integer"/>
<xsd:attribute name="nickName" type="nickName"/> <!-- 属性引用时name和ref属性不能同时出现 -->
</xsd:complexType>
<xsd:simpleType name="nickName">
<xsd:list itemType="xsd:string"/>
</xsd:simpleType>
</xsd:schema>
5.在项目的根类路径配置自定义标签命名空间、解析器等信息: META-INF
注意:文件名这2个文件名不能自定义修改,Spring框架内部对文件名进行了硬编码指定。
spring.handlers
http\://www.zhiwei.com/schema/user=com.zhiwei.basic.tag.NamespaceHandler
spring.schemas
http\://www.zhiwei.com/schema/user/user.xsd=com/zhiwei/basic/tag/user.xsd
6.测试自定义标签
Spring配置文件:
<?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:dubbo="http://www.zhiwei.com/schema/user"
xsi:schemaLocation="
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
http://www.zhiwei.com/schema/user http://www.zhiwei.com/schema/user/user.xsd">
<dubbo:user id="user" userName="cong" email="mail.163.com"/>
<!-- 定义List类型的Bean -->
<dubbo:person id="person" personName="zhangsan" age="10" nickName="zhangsan,lisi,wangwu"/>
</beans>
测试类:
package com.zhiwei.basic.tag;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class MainTest {
@SuppressWarnings("resource")
public static void main(String[] args) {
ApplicationContext ac = new ClassPathXmlApplicationContext("com/zhiwei/basic/tag/applicationContext.xml");
User user = (User) ac.getBean("user");
System.out.println("user--------" + user);
Person person = (Person) ac.getBean("person");
System.out.println("person---------"+person);
}
}
效果:
项目层次图: