一、源码分析:
Spring标签的定义分为默认标签和
自定义标签
Spring源代码:[
DefaultBeanDefinitionDocumentReader.java]
class="java">
/**
* Parse the elements at the root level in the document:
* "import", "alias", "bean".
* @param root the DOM root element of the document
*/
protected void parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate) {
//对beans的处理
if (delegate.isDefaultNamespace(root)) {
NodeList nl = root.getChildNodes();
for (int i = 0; i < nl.getLength(); i++) {
Node node = nl.item(i);
if (node instanceof Element) {
Element ele = (Element) node;
if (delegate.isDefaultNamespace(ele)) {
//对默认标签处理
parseDefaultElement(ele, delegate);
}
else { //对自定义标签处理
delegate.parseCustomElement(ele);
}
}
}
}
else { //对自定义标签处理
delegate.parseCustomElement(root);
}
}
Spring其他集成组件如SpringMVC使用了自定义标签。
二、实现自定义标签
步骤:
1、创建一个需要扩展的组件。
如:定义一个User来接受xml文件信息
package ppfuns;
/**
* Created with IntelliJ IDEA.
* User: **
* Date: 2017/11/22
* Time: 10:09
* To change this template use File | Settings | File Templates.
*/
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文件描述
主键内容。
如创建了一个user.xsd文件
<?xml version="1.0" encoding="utf-8"?>
<schema xmlns="http://www.w3.org/2001/XMLSchema"
targetNamespace="http://www.lexueba.com/schema/user"
xmlns:tns="http://www.lexueba.com/schema/user"
elementFormDefault="qualified">
<element name="user">
<complexType>
<attribute name="id" type="string"/>
<attribute name="userName" type="string"/>
<attribute name="email" type="string"/>
</complexType>
</element>
</schema>
3、创建一个文件、实现BeanDefinitionParser
接口,用来
解析XSD文件中的定义和组件定义
package ppfuns.parser;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.xml.AbstractSingleBeanDefinitionParser;
import org.springframework.util.StringUtils;
import org.w3c.dom.Element;
import ppfuns.User;
/**
* Created with IntelliJ IDEA.
* User: 简德群
* Date: 2017/11/22
* Time: 10:22
* To change this template use File | Settings | File Templates.
*/
public class UserBeanDefinitionParser extends AbstractSingleBeanDefinitionParser {
/**
* Element 对应的元素User
* @param element
* @return
*/
protected Class getBeanClass(Element element){
return User.class;
}
/**
* 从element元素中提取对应元素的值
* @param element
* @param builder
*/
@Override
protected void doParse(Element element, BeanDefinitionBuilder builder) {
String username = element.getAttribute("name");
String email = element.getAttribute("email");
if(StringUtils.hasText(username)){
builder.addPropertyValue("name",username);
}
if(StringUtils.hasText(email)){
builder.addPropertyValue("email",email);
}
}
}
4、创建一个handler文件,扩展自NamespaceHandlerSupport,目的是将组件注册到Spring容器中
package ppfuns.parser;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.xml.AbstractSingleBeanDefinitionParser;
import org.springframework.util.StringUtils;
import org.w3c.dom.Element;
import ppfuns.User;
/**
* Created with IntelliJ IDEA.
* User: 简德群
* Date: 2017/11/22
* Time: 10:22
* To change this template use File | Settings | File Templates.
*/
public class UserBeanDefinitionParser extends AbstractSingleBeanDefinitionParser {
/**
* Element 对应的元素User
* @param element
* @return
*/
protected Class getBeanClass(Element element){
return User.class;
}
/**
* 从element元素中提取对应元素的值
* @param element
* @param builder
*/
@Override
protected void doParse(Element element, BeanDefinitionBuilder builder) {
String username = element.getAttribute("name");
String email = element.getAttribute("email");
if(StringUtils.hasText(username)){
builder.addPropertyValue("name",username);
}
if(StringUtils.hasText(email)){
builder.addPropertyValue("email",email);
}
}
}
5、编写spring.handlers和Spring.schemas文件。这两个文件需放在resources/META-INF下
spring.handlers文件:指定NamespaceHander位置
http\://www.lexueba.com/schema/user=ppfuns.parser.MyNameSpaceHandler
spring.schemas文件:指定xsd文件映射位置
http\://www.lexueba.com/schema/user/user.xsd=user.xsd
上面已经完成了对自定义标签的实现,那接下来就测试一下咯
spring-user.xml文件定义
<?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:myName="http://www.lexueba.com/schema/user"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.2.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.2.xsd
http://www.lexueba.com/schema/user
http://www.lexueba.com/schema/user/user.xsd"
>
<myName:user id="userBean" userName="jiandequn" email="9780307441@qq.com" ></myName:user>
</beans>
Test运行代码:
package ppfuns.junit;
import junit.framework.Assert;
import org.junit.Test;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.xml.XmlBeanFactory;
import org.springframework.core.io.ClassPathResource;
import ppfuns.lookup.TestAbstractLookupMethod;
import ppfuns.replaceMethod.ReplacedMethodTest;
/**
* Created with IntelliJ IDEA.
* User: 简德群
* Date: 2017/11/27
* Time: 9:56
* To change this template use File | Settings | File Templates.
*/
public class JunitTest {
@Test
public void test(){
BeanFactory bf = new XmlBeanFactory(new ClassPathResource("spring-user.xml"));
ppfuns.User t1 = (ppfuns.User) bf.getBean("userBean");
Assert.assertSame(t1,t1);
System.out.println(t1.getUsername()+","+t1.getEmail());
}
}
说明:如想了解具体实现看《Spring源码深度解析》的第4章节