1概述
在上一篇文章中讲到Spring通过实现接口BeanDefinitionDocumentReader的DefaultBeanDefinitionDocumentReader类对Document进行解析,并使用BeanDefinitionParserDelegate对Element进行解析。
解析自定义标签实现
@Nullable
public BeanDefinition parseCustomElement(Element ele) {
return parseCustomElement(ele, null);
}
@Nullable
public BeanDefinition parseCustomElement(Element ele, @Nullable BeanDefinition containingBd) {
String namespaceUri = getNamespaceURI(ele);
if (namespaceUri == null) {
return null;
}
// 处理NamespaceHandler,并调用NamespaceHandler的init方法
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));
}
处理NamespaceHandler,并调用NamespaceHandler的init方法
@Override
@Nullable
public NamespaceHandler resolve(String namespaceUri) {
Map<String, Object> handlerMappings = getHandlerMappings();
Object handlerOrClassName = handlerMappings.get(namespaceUri);
if (handlerOrClassName == null) {
return null;
}
else if (handlerOrClassName instanceof NamespaceHandler) {
return (NamespaceHandler) handlerOrClassName;
}
else {
String className = (String) handlerOrClassName;
try {
Class<?> handlerClass = ClassUtils.forName(className, this.classLoader);
if (!NamespaceHandler.class.isAssignableFrom(handlerClass)) {
throw new FatalBeanException("Class [" + className + "] for namespace [" + namespaceUri +
"] does not implement the [" + NamespaceHandler.class.getName() + "] interface");
}
NamespaceHandler namespaceHandler = (NamespaceHandler) BeanUtils.instantiateClass(handlerClass);
namespaceHandler.init();
handlerMappings.put(namespaceUri, namespaceHandler);
return namespaceHandler;
}
catch (ClassNotFoundException ex) {
throw new FatalBeanException("Could not find NamespaceHandler class [" + className +
"] for namespace [" + namespaceUri + "]", ex);
}
catch (LinkageError err) {
throw new FatalBeanException("Unresolvable class definition for NamespaceHandler class [" +
className + "] for namespace [" + namespaceUri + "]", err);
}
}
}
获取解析器,解析标签
@Override
public BeanDefinition parse(Element element, ParserContext parserContext) {
return findParserForElement(element, parserContext).parse(element, parserContext);
}
2 自定义标签实现
2.1 主要类:
AbstractSingleBeanDefinitionParser :继承自BeanDefinitionParser接口,用于对XSD解析
NamespaceHandlerSupport:用于注册组件
2.2 创建自定义标签流程:
- 创建一个需要扩展的组件
- 定义一个XSD文件描述组件内容
- 创建一个文件,实现BeanDefinitionParser接口,用来解析XSD文件中的定义和组件定义
- 创建一个Handler文件,扩展NamespaceHandlerSupport,目的是将组件注册到Spring容器中
- 编写Spring.handlers和Spring.schemas文件
2.3 实现自定义标签:
(1) 首先我们定义一个普通的POJO
package com.gz.spring.customElement;
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) 定义一个XSD文件描述内容
<?xml version="1.0" encoding="UTF-8"?>
<schema xmlns="http://www.w3.org/2001/XMLSchema"
xmlns:tns="http://www.gz.com/schema/user"
targetNamespace="http://www.gz.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 com.gz.spring.customElement;
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);
}
}
}
(4) 创建一个Handler文件,扩展NamespaceHandlerSupport,目的是将组件注册到Spring容器中。
package com.gz.spring.customElement;
import org.springframework.beans.factory.xml.NamespaceHandlerSupport;
public class MyUserNamespaceHandler extends NamespaceHandlerSupport {
@Override
public void init() {
registerBeanDefinitionParser("user",new UserBeanDefinitionParser());
}
}
(5) 编写spring.handlers和spring.schemas文件,默认位置在工程/META-INF/文件下
spring.handlers:
http\://www.gz.com/schema/user=com.gz.spring.customElement.MyUserNamespaceHandler
spring.schemas:
http\://www.gz.com/schema/user.xsd=META-INF/spring-user.xsd