您的位置:首页 > 编程语言 > Java开发

[置顶] Spring 源码解析 ---- 自定义标签

2016-11-15 20:21 555 查看
零. 阅读准备

读这篇文章前先看下预备知识:Spring 自定义标签




一. 代码阅读
自定义标签解析核心代码:
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));
}

可以看出 Spring 代码逻辑很清晰:
getNamespaceURI() 获取自定义标签的 namespace
而后使用 namespace 获取相应处理的 handler
最后由 handler 指定的 parser 来解析自定义的标签

(1) getNamespaceURI() 获取自定义标签的 namespace
public String getNamespaceURI(Node node) {
return node.getNamespaceURI();
}

就是常规的 XML 内容提取

(2)而后使用 namespace 获取相应处理的 handler

debug 到这一步发现是使用了 NamespaceHandlerResolver 的实现类 DefaultNamespaceHandlerResolver 来获取对应的 handler
@Override
public NamespaceHandler resolve(String namespaceUri) {
// 获取所有配置在 spring.handlers 中的映射
Map<String, Object> handlerMappings = getHandlerMappings();
// 从映射关系中取出相应的value
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);
// 类有了,就调用我们为自定义标签重写过的 init 方法
namespaceHandler.init();
// 放入缓存
handlerMappings.put(namespaceUri, namespaceHandler);
return namespaceHandler;
}
catch (ClassNotFoundException ex) {
throw new FatalBeanException("NamespaceHandler class [" + className + "] for namespace [" +
namespaceUri + "] not found", ex);
}
catch (LinkageError err) {
throw new FatalBeanException("Invalid NamespaceHandler class [" + className + "] for namespace [" +
namespaceUri + "]: problem with handler class file or dependent class", err);
}
}
}


放入缓存后,我们可以看到缓存中已经有了我们为自定义标签新增的 handler:








(3)最后由 handler 指定的 parser 来解析自定义的标签



@Override
public BeanDefinition parse(Element element, ParserContext parserContext) {
return findParserForElement(element, parserContext).parse(element, parserContext);
}

private BeanDefinitionParser findParserForElement(Element element, ParserContext parserContext) {
// 获取 wenniuwuren:user 中的 user
String localName = parserContext.getDelegate().getLocalName(element);
// 根据 user 找到对应的 parser
BeanDefinitionParser parser = this.parsers.get(localName);
if (parser == null) {
parserContext.getReaderContext().fatal(
"Cannot locate BeanDefinitionParser for element [" + localName + "]", element);
}
return parser;
}

@Override
public final BeanDefinition parse(Element element, ParserContext parserContext) {
// 使用自定义的 Parser 将 element 中的东西读取到 BeanDefinition 中
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;
if (shouldParseNameAsAliases()) {
String name = element.getAttribute(NAME_ATTRIBUTE);
if (StringUtils.hasLength(name)) {
aliases = StringUtils.trimArrayElements(StringUtils.commaDelimitedListToStringArray(name));
}
}
// 将 AbstractBeanDefinition 转换为 BeanDefinitionHolder
BeanDefinitionHolder holder = new BeanDefinitionHolder(definition, id, aliases);
// 注册 holder
registerBeanDefinition(holder, parserContext.getRegistry());
if (shouldFireEvents()) {
BeanComponentDefinition componentDefinition = new BeanComponentDefinition(holder);
postProcessComponentDefinition(componentDefinition);
parserContext.registerComponent(componentDefinition);
}
}
catch (BeanDefinitionStoreException ex) {
parserContext.getReaderContext().error(ex.getMessage(), element);
return null;
}
}
return definition;
}


到此,自定义标签的数据就从配置文件加载到了内存,自定义标签的解析其实就是 Spring 提供给开发者的扩展使用,整体解析过程和 Spring 默认的标签类似。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: