之前说过spring解析自定义配置之spring.handlers/spring.schemas,来解析一些自定义标签,是以dubbo为例说明的。dubbo中的spring.handlers文件中定义了DubboNamespaceHandler类,其代码如下,spring容器启动时,会调用其init方法加载对应的标签解析器。
public class DubboNamespaceHandler extends NamespaceHandlerSupport {
static {
Version.checkDuplicate(DubboNamespaceHandler.class);
}
@Override
public void init() {
//application标签处理
registerBeanDefinitionParser("application", new DubboBeanDefinitionParser(ApplicationConfig.class, true));
registerBeanDefinitionParser("module", new DubboBeanDefinitionParser(ModuleConfig.class, true));
registerBeanDefinitionParser("registry", new DubboBeanDefinitionParser(RegistryConfig.class, true));
registerBeanDefinitionParser("monitor", new DubboBeanDefinitionParser(MonitorConfig.class, true));
registerBeanDefinitionParser("provider", new DubboBeanDefinitionParser(ProviderConfig.class, true));
registerBeanDefinitionParser("consumer", new DubboBeanDefinitionParser(ConsumerConfig.class, true));
registerBeanDefinitionParser("protocol", new DubboBeanDefinitionParser(ProtocolConfig.class, true));
//service标签处理
registerBeanDefinitionParser("service", new DubboBeanDefinitionParser(ServiceBean.class, true));
registerBeanDefinitionParser("reference", new DubboBeanDefinitionParser(ReferenceBean.class, false));
registerBeanDefinitionParser("annotation", new AnnotationBeanDefinitionParser());
}
}
之后spring处理节点会有如下操作:
/**
* 处理节点返回BeanDefinition(bean定义)
*/
@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 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,其实就是我们所看到的DubboNamespaceHandler,其继承关系如下:
解析的时候会将其缓存起来,这里直接取用就行了,这里会调用其parse方法进行解析,而DubboNamespaceHandler中parse方法是在其父类NamespaceHandlerSupport中实现的,其代码如下:
/**
* Parses the supplied {@link Element} by delegating to the {@link BeanDefinitionParser} that is
* registered for that {@link Element}.
*
* 解析节点信息返回BeanDefinition 这里通过委派给BeanDefinitionParser进行处理
*/
@Override
@Nullable
public BeanDefinition parse(Element element, ParserContext parserContext) {
//获取BeanDefinitionParser
BeanDefinitionParser parser = findParserForElement(element, parserContext);
//调用BeanDefinitionParser对象的parse方法进行处理
return (parser != null ? parser.parse(element, parserContext) : null);
}
/**
* Locates the {@link BeanDefinitionParser} from the register implementations using
* the local name of the supplied {@link Element}.
* 获取BeanDefinitionParser
*/
@Nullable
private BeanDefinitionParser findParserForElement(Element element, ParserContext parserContext) {
//获取localName
String localName = parserContext.getDelegate().getLocalName(element);
//获取parser
BeanDefinitionParser parser = this.parsers.get(localName);
if (parser == null) {
parserContext.getReaderContext().fatal(
"Cannot locate BeanDefinitionParser for element [" + localName + "]", element);
}
return parser; //返回
}
这里并未进行实际的操作,只是获取对应的BeanDefinitionParser,然后将任务委派给BeanDefinitionParser执行,而这里的BeanDefinitionParser正是在init方法中注入的信息,代码如下:
@Override
public void init() {
//application标签处理
registerBeanDefinitionParser("application", new DubboBeanDefinitionParser(ApplicationConfig.class, true));
registerBeanDefinitionParser("module", new DubboBeanDefinitionParser(ModuleConfig.class, true));
registerBeanDefinitionParser("registry", new DubboBeanDefinitionParser(RegistryConfig.class, true));
registerBeanDefinitionParser("monitor", new DubboBeanDefinitionParser(MonitorConfig.class, true));
registerBeanDefinitionParser("provider", new DubboBeanDefinitionParser(ProviderConfig.class, true));
registerBeanDefinitionParser("consumer", new DubboBeanDefinitionParser(ConsumerConfig.class, true));
registerBeanDefinitionParser("protocol", new DubboBeanDefinitionParser(ProtocolConfig.class, true));
//service标签处理
registerBeanDefinitionParser("service", new DubboBeanDefinitionParser(ServiceBean.class, true));
registerBeanDefinitionParser("reference", new DubboBeanDefinitionParser(ReferenceBean.class, false));
registerBeanDefinitionParser("annotation", new AnnotationBeanDefinitionParser());
}
protected final void registerBeanDefinitionParser(String elementName, BeanDefinitionParser parser) {
this.parsers.put(elementName, parser);
}
如此以来,我们便能够使用自定义的解析器去解析我们自定义的标签返回一个BeanDefinition加到spring容器中。