网上也有很多示例代码,当然,有的能运行起来,有的却是不能测试运行。于是就自己动手写了这示例。但是走了不少弯路。希望对后来者也有所帮助。共勉。
首先,看这篇博文要有对spring有一定了解,还有对xsd schema文档定义语言也要有所知。不多说上代码。
定义一个普通的javaBean(很简单的,没有什么逻辑)如下:
package com.wjs.cosumertag;
public class User {
private String id;
private String userName;
private String email;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
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;
}
}
然后定义一个AbstractSingleBeanDefinitionParser,实现这个类里面的一个doParser和getBeanClass方法如下:
package com.wjs.cosumertag;
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 {
@Override
protected Class> getBeanClass(Element element) {
return User.class;
}
@Override
protected void doParse(Element element, BeanDefinitionBuilder builder) {
String userName=element.getAttribute("userName");
String email=element.getAttribute("email");
if(StringUtils.hasText(userName)){
builder.addPropertyValue("userName", userName);
}
if(StringUtils.hasText(email)){
builder.addPropertyValue("email", email);
}
}
}
注意:类不要导入错了。
接下来,定义一个nameSpaceHandler,用于注册到Spring框架里面,在spring解析算定义标签的时候可以用我们自定义的处理方式。如下:
package com.wjs.cosumertag;
import org.springframework.beans.factory.xml.NamespaceHandlerSupport;
public class MyUserNamespaceHandler extends NamespaceHandlerSupport {
@Override
public void init() {
registerBeanDefinitionParser("user",new UserBeanDefinitionParser());
}
}
以上这两个类,便是处理自定义标签的处理类。
接下来就是xml schema definition (xsd)文件以及一些配置文件的配置。
创建一个xsd为后缀的文件spring-user.xsd,内容如下:
其中,xmlns=xmlns="http://www.wjs.com/schema/user",targetNamespace="http://www.wjs.com/schema/user" 这两个是自己定义的值,作用下面叙述。
然后就是配置这个xsd文件,让spring能够找到这个约束文件。
在classpath下创建一文件夹META-INF,然后创建两个文件spring.handlers和spring.schemas,(注意:这两个文件名不能改的)其中:为什么要创建MEAT-INF文件夹,spring是默认的向这个文件夹里面寻找这两个文件,如果想修改,就要修改spring源码来实现。
spring.handlers文件内容如下:
http\://www.wjs.com/schema/user=com.wjs.cosumertag.MyUserNamespaceHandler
spring.schemas文件内容如下:
http\://www.wjs.com/schema/user.xsd=META-INF/spring-user.xsd
注意:冒号要进行转义
接下来就是在spring核心配置文件配置使用,文件名application-customtag.xml内容如下:
其中,xmlns:myTag="http://www.wjs.com/schema/user";http://www.wjs.com/schema/user;http://www.wjs.com/schema/user.xsd,这三个地方是自己定义的值,为什么这样写:spring在解析xml的时候,会根据namespaceURI来判断是spring的默认标签,还是用户定义的标签。下面翻下spring代码来说明:
protected void parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate) {
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);
}
}
而parseCustomElement文件如下:
public BeanDefinition parseCustomElement(Element ele, BeanDefinition containingBd) {
String namespaceUri = getNamespaceURI(ele);
NamespaceHandler handler = this.readerContext.getNamespaceHandlerResolver().resolve(namespaceUri);
if (handler == null) {
error("Unable to locate Spring NamespaceHandler for XML schema namespace [" + namespaceUri + "]", ele);
return null;
}
return handler.parse(ele, new ParserContext(this.readerContext, this, containingBd));
}
首先是获取 namespaceUri这个值就是在spring.handlers里面定义的http\://www.wjs.com/schema/user,在sping启动时,会加载所有的namespaceURL做为一个map的key,此时这个key=http://www.wjs.com/schema/user.xsd,也就是spring解析现来的SystemId,而值就是META-INF/spring-test.xml,去这个目录下读取相应的sxd文件。如对spring源码有兴趣可以自行去翻阅下,会有不少的收获。package com.wjs.cosumertag;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class CustomerTagTest {
public static void main(String[] args) {
ApplicationContext beans=new ClassPathXmlApplicationContext("classpath:application-customtag.xml");
User user=(User)beans.getBean("testBean");
System.out.println("username:"+user.getUserName()+":"+"email:"+user.getEmail());
}
}
如果不出意外,运行结果会是这样:
其中走过的弯路如下:
1.META-INF下的文件夹下的两个文件名,写成了大写Spring.handlers和Spring.schemas,导致找不到文件;没有加上xsd:前缀,导致解析spring-user.xsd文件报错。
2.在编写spring-test.xsd文件时,没有加xsd:导致提示文件提前结束报错问题。 3.在编写spring-customtag.xml时,一定按照spring.handler和spring.schemas文件里的定义内容去添加自定义标签的namespaceURI.