-
Spring 源码阅读-2-自定义标签简单使用与解析
自定义标签解析
1、自定义标签的使用
在探究自定义标签的解析过程前,温顾一下使用会更方便解析过程的理解。
定义XSD文件
<?xml version="1.0"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
targetNamespace="http://www.w3school.com.cn"
xmlns="http://www.w3school.com.cn"
elementFormDefault="qualified">
<element name="user">
<complexType>
<attribute name="id" type="String"></attribute>
<attribute name="userName" type="String"></attribute>
<attribute name="email" type="String"></attribute>
</complexType>
</element>
</xs:schema>
XSD 如何定义可以看w3c中XML Schema中的教程
定义实体类
public class User{
private String id;
private String userName;
private String email;
// 省略 set/get 方法
}
实现BeanDefinitionParser接口
/**
* 自定义标签的解析器
*/
public class UserBeanDefinitionParser extends AbstractSingleBeanDefinitionParser {
@Override
protected Class<?> getBeanClass(Element element) {
return User.class;
}
/**
* 用来解析自定义的标签
*/
@Override
protected void doParse(Element element, BeanDefinitionBuilder bean) {
// 获取自定义标签属性
String userName = element.getAttribute("userName");
String email = element.getAttribute("email");
bean.addPropertyValue("userName",userName);
bean.addPropertyValue("email",email);
}
}
扩展NamespaceHandlerSupport
import org.springframework.beans.factory.xml.NamespaceHandlerSupport;
public class CustomNamespaceHandlerSupport extends NamespaceHandlerSupport {
@Override
public void init() {
registerBeanDefinitionParser("user", new UserBeanDefinitionParser());
}
}
配置此代码后,当遇到自定义标签user:xxxx,user开头的自定义标签的元素时,就会使用UserBeanDefinitionParser解析器解析。
配置schema文件路径以及handler
默认在META-INF文件夹下配置
Spring.handlers
http://www.w3school.com.cn/schema/user=com.yxx.CustomNamespaceHandlerSupport
Spring.schemes
http://www.w3school.com.cn/schema/user.xsd=META-INF/Spring-test.xsd
配置此信息可以让Spring找到xsd文件以及自定义NamespaceHandlerSupport
2、自定义标签解析
回到在默认标签解析时候的方法
DefaultBeanDefinitionDocumentReader#parseBeanDefinitions
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) {
// 对 bean处理
Element ele = (Element) node;
if (delegate.isDefaultNamespace(ele)) {
// 处理 默认的 http //w ww.springframework org/scherna beans
parseDefaultElement(ele, delegate);
}
else {
// 处理自定义的 比如 tx下的
delegate.parseCustomElement(ele);
}
}
}
}
else {
delegate.parseCustomElement(root);
}
}
解析自定义标签
BeanDefinitionParserDelegate#parseCustomElement
public BeanDefinition parseCustomElement(Element ele, @Nullable BeanDefinition containingBd) {
// 获取 命名空间 namespaceUri http://xxxxx.xsd
// w3c提供的Node 提供了方法
String namespaceUri = getNamespaceURI(ele);
if (namespaceUri == null) {
return null;
}
// 提取自定义的标签处理器
// 通过命名空间获取对应的namespacehandler
NamespaceHandler handler = this.readerContext.getNamespaceHandlerResolver().resolve(namespaceUri);
if (handler == null) {
error("Unable to locate Spring NamespaceHandler for XML schema namespace [" + namespaceUri + "]", ele);
return null;
}
// 使用自定自定义的 namespacehandler 进行解析
// 例如 <myname:user> namespacehandler 可以解析全部的 myname 命名空间的 标签
// 命名空间处理器 namespacehandler 通过 不同的标签调用不同的 AbstractSingleBeanDefitionParser
return handler.parse(ele, new ParserContext(this.readerContext, this, containingBd));
}
此方法中首先获取此ele的命名空间,并通过命名空间处理程序解析器(DefaultNamespaceHandlerResolver)根绝命名空间名称获取命名空间处理器(NamespaceHandler),然后通过parse方法处理自定义标签(实际上此方法执行的就是UserBeanDefinitionParser#doParse)。
DefaultNamespaceHandlerResolver#resolve
public NamespaceHandler resolve(String namespaceUri) {
// 获取handler mapper -----> 其实就是Spring.handlers 中配置的namespace-handler
Map<String, Object> handlerMappings = getHandlerMappings();
// 查看此namespace是否存在对应的handler
Object handlerOrClassName = handlerMappings.get(namespaceUri);
// 不存在
if (handlerOrClassName == null) {
return null;
}
// 如果存在缓存 直接返回
else if (handlerOrClassName instanceof NamespaceHandler) {
return (NamespaceHandler) handlerOrClassName;
}
else {
// 存的是className
String className = (String) handlerOrClassName;
try {
// 获取对应的classname 的Class对象
Class<?> handlerClass = ClassUtils.forName(className, this.classLoader);
// 判断此Class 是否 集成实现 NamespaceHandler
if (!NamespaceHandler.class.isAssignableFrom(handlerClass)) {
throw new FatalBeanException("Class [" + className + "] for namespace [" + namespaceUri +
"] does not implement the [" + NamespaceHandler.class.getName() + "] interface");
}
// 实例化 namespacehandler 并类型转换
NamespaceHandler namespaceHandler = (NamespaceHandler) BeanUtils.instantiateClass(handlerClass);
// 初始化
// 将AbstractSingleBeanDefitionParser实例化并 注册到BeanDefnitionParser缓存中, registerBeanDefnitionParser
namespaceHandler.init();
// 将namespacehandler添加到缓存
handlerMappings.put(namespaceUri, namespaceHandler);
return namespaceHandler;
}
...
}
}
handlerMappings此Map缓存中存放的为namespace-handler的映射,但是这个handler可能是已经实例化的NamespaceHandler,也可能是handlerClassName,如果是handlerClassName,需要先实例化再添加到缓存
NamespaceHandlerSupport#parse
public BeanDefinition parse(Element element, ParserContext parserContext) {
// 查找 parserContext 对应的 的解析器
BeanDefinitionParser parser = findParserForElement(element, parserContext);
// parser不为空 就解析标签, 并将beanDefinition注册到Spring容器中
return (parser != null ? parser.parse(element, parserContext) : null);
}
将任务分解,首先查找出该ele解析的BeanDefinitionParser,然后进行解析,最后会执行UserBeanDefinitionParser#doParse。
NamespaceHandlerSupport#findParserForElement
@Nullable
private BeanDefinitionParser findParserForElement(Element element, ParserContext parserContext) {
// 获取<myname:user> 中的user
String localName = parserContext.getDelegate().getLocalName(element);
// registerBeanDefinitionParser (”user ”, new UserBeanDefinitionParser ()) ; 这里已经将 user --解析器保存在了 map中
// 获取user对应的解析器
BeanDefinitionParser parser = this.parsers.get(localName);
if (parser == null) {
parserContext.getReaderContext().fatal(
"Cannot locate BeanDefinitionParser for element [" + localName + "]", element);
}
return parser;
}
解析完成
AbstractBeanDefinitionParser#parse
public final BeanDefinition parse(Element element, ParserContext parserContext) {
// 解析自定义标签除去默认属性的其他属性以及子标签
AbstractBeanDefinition definition = parseInternal(element, parserContext);
if (definition != null && !parserContext.isNested()) {
try {
String id = resolveId(element, definition, parserContext);
if (!StringUtils.hasText(id)) {
parserContext.getReaderContext().error(
"Id is required for element '" + parserContext.getDelegate().getLocalName(element)
+ "' when used as a top-level tag", element);
}
String[] aliases = null;
// 解析 name 分割成别名
if (shouldParseNameAsAliases()) {
String name = element.getAttribute(NAME_ATTRIBUTE);
if (StringUtils.hasLength(name)) {
aliases = StringUtils.trimArrayElements(StringUtils.commaDelimitedListToStringArray(name));
}
}
// 构造BeanDefinitionHolder对象
BeanDefinitionHolder holder = new BeanDefinitionHolder(definition, id, aliases);
// 注册beanDefinition
registerBeanDefinition(holder, parserContext.getRegistry());
if (shouldFireEvents()) {
BeanComponentDefinition componentDefinition = new BeanComponentDefinition(holder);
postProcessComponentDefinition(componentDefinition);
parserContext.registerComponent(componentDefinition);
}
}
catch (BeanDefinitionStoreException ex) {
String msg = ex.getMessage();
parserContext.getReaderContext().error((msg != null ? msg : ex.toString()), element);
return null;
}
}
return definition;
}
AbstractSingleBeanDefinitionParser#parseInternal
@Override
protected final AbstractBeanDefinition parseInternal(Element element, ParserContext parserContext) {
// 创建 BeanDefinition 构造器
BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition();
// getParentName 由子类去实现 获取父类名字
String parentName = getParentName(element);
if (parentName != null) {
builder.getRawBeanDefinition().setParentName(parentName);
}
// getBeanClass 由子类重写获取当前标签对应的类类型 返回Class
Class<?> beanClass = getBeanClass(element);
if (beanClass != null) {
builder.getRawBeanDefinition().setBeanClass(beanClass);
}
else {
// getBeanClassName 由子类重写获取当前标签对应的类类型 字符串
String beanClassName = getBeanClassName(element);
if (beanClassName != null) {
builder.getRawBeanDefinition().setBeanClassName(beanClassName);
}
}
builder.getRawBeanDefinition().setSource(parserContext.extractSource(element));
BeanDefinition containingBd = parserContext.getContainingBeanDefinition();
// 存在父类
if (containingBd != null) {
// Inner bean definition must receive same scope as containing bean.
builder.setScope(containingBd.getScope());
}
if (parserContext.isDefaultLazyInit()) {
// Default-lazy-init applies to custom bean definitions as well.
builder.setLazyInit(true);
}
// 子类重写的 解析方法
doParse(element, parserContext, builder);
return builder.getBeanDefinition();
}
此方法解析parent、beanClass以及继承父类的scope和是否懒加载,并最终调用doParse方法实现自定义标签的处理,doParse此方法就为UserBeanDefinitionParser#doParse
来源:https://www.cnblogs.com/aismvy/p/15561182.html