spring 源码探索--xml的自定义标签解析

时间:2022-08-20 20:36:25
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

  1. 获取命名空间
  2. 通过命名空间找到对应的handler处理器
  3. 使用解析器BeanDefinitionParser解析自定义标签

如果想在spring中实现自定义标签的功能。

  1. 创建一个解析自定义标签的解析器,解析xml自定义标签
  2. 创建一个handler,将解析器组件注入到spring容器中
  3. 定义命名空间spring.handlers 和 spring.schemas
    spring.handlers文件中定义的是命名空间和命名空间handler的映射关系
    默认位置是/META-INF/文件夹下
  4. 创建一个需要自定义标签定义的组件(javaBean)
  5. 定义一个XSD文件描述组件的内容
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));
}
  • get namespaceUri
    使用默认的Node实现

  • get namespaceHandler
    首先获取所有的handlerMappings,默认是META-INF/Spring.handlers
    获得指定handler,init。
    找到自定义标签的handler,执行init方法,
    再调用NamespaceHandlerSupport的registerBeanDefinitionParser(elementName,BeanDefinitionParser)把自定义命名空间和解析器连接起来。

String className = (String) handlerOrClassName;
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;
  • 找到对应的parser进行解析
    AbstractBeanDefinitionParser 中调用parse方法进行解析,再调用parseInternal得到AbstractBeanDefinition,这里面会调用到用户自定义的解析器的doParse,这个接口是继承的抽象类AbstractSingleBeanDefinitionParser的。

  • 注册beanDefinition

  • 有需要的话,通知监听器事件fireEvent.

偶尔问自己几个问题:

自定义标签解析,注册自定义的parser的时机是在什么时候?
xmlBeanDefiniationReader get Element root, parse element
BeanDefinitionDocumentReader ready to parse element.
简单地说是在开始解析自定义标签的时候,类:BeanDefinitionParserDelegate parseCustomElement.
再委托给DefaultNamespaceResolver得到具体的handler.
执行resolve过程
namespaceUri 就是http://www.springframework.org/schema/aop
1. getHandlerMappings spring.handlers
2. get handler from mapping by namespaceUri
3. 实例化
4. 执行init方法,该方法里面就实现了自定义标签和parse的映射关系
5. 存入HandlerMappings中,备用
返回namespaceHandler,
3. execute namespaceHandlerSupport parse method
4. execute custom doParse method.