xml配置dubbo标签的解析
可以参考之前的一篇文章 spring引入servicebean,该文章提到更多的是spring自定义tag的实现,对于理解dubbo标签解析有一定的帮助。
<dubbo:application name="demo-provider"/><!-- use dubbo protocol to export service on port 20880 -->
<dubbo:protocol name="dubbo"/>
对于上面这样的两行定义spring是如何解析的呢?
首先是要处理这种非spring的dubbo自定义标签,如何解析请参照spring引入servicebean,参照文档开头贴出了一段代码,如下:
@Override
public void init() {registerBeanDefinitionParser("application", new DubboBeanDefinitionParser(ApplicationConfig.class, true));registerBeanDefinitionParser("module", new DubboBeanDefinitionParser(ModuleConfig.class, true));registerBeanDefinitionParser("registry", new DubboBeanDefinitionParser(RegistryConfig.class, true));registerBeanDefinitionParser("config-center", new DubboBeanDefinitionParser(ConfigCenterBean.class, true));registerBeanDefinitionParser("metadata-report", new DubboBeanDefinitionParser(MetadataReportConfig.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));registerBeanDefinitionParser("service", new DubboBeanDefinitionParser(ServiceBean.class, true));registerBeanDefinitionParser("reference", new DubboBeanDefinitionParser(ReferenceBean.class, false));registerBeanDefinitionParser("annotation", new AnnotationBeanDefinitionParser());
}
然后介绍了如何解析spring自定义标签的流程,但是没有解开dubbo自定义标签最终是如何处理的,下面我们就接着上篇文章聊下dubbo标签是如何解析的。
首先看这里:
/*** Parse a custom element (outside of the default namespace).* @param ele the element to parse* @param containingBd the containing bean definition (if any)* @return the resulting bean definition*/
@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));
}
最后一行代码调用了handler.parse方法,对应到dubbo,则此处的handler为DubboNamespaceHandler,该类继承了NamespaceHandlerSupport,看一下这个父类的一些属性和方法就能找到答案了。
/*** Stores the {@link BeanDefinitionParser} implementations keyed by the* local name of the {@link Element Elements} they handle.*/
// 1、属性
private final Map<String, BeanDefinitionParser> parsers = new HashMap<String, BeanDefinitionParser>();/*** Parses the supplied {@link Element} by delegating to the {@link BeanDefinitionParser} that is* registered for that {@link Element}.*/
// 2、因为子类没有实现此方法,所以此处便对应了上文提到的handler.parse方法
@Override
public BeanDefinition parse(Element element, ParserContext parserContext) {// 3、首先是获取parser,一会我们看下这个逻辑;// 4、调用获取到的parser的parse方法,此方法便对应着DubboBeanDefinitionParser的parse方法return findParserForElement(element, parserContext).parse(element, parserContext);
}/*** Locates the {@link BeanDefinitionParser} from the register implementations using* the local name of the supplied {@link Element}.*/
// 5、上述代码3处对应的逻辑
private BeanDefinitionParser findParserForElement(Element element, ParserContext parserContext) {String localName = parserContext.getDelegate().getLocalName(element);// 6、此处的parsers则是开篇代码里registerBeanDefinitionParser方法注册的内容,即key=dubbo标签内容,如service,value=DubboBeanDefinitionParserBeanDefinitionParser parser = this.parsers.get(localName);if (parser == null) {parserContext.getReaderContext().fatal("Cannot locate BeanDefinitionParser for element [" + localName + "]", element);}return parser;
}
代码里已经加了注释,相信大家已经基本理解dubbo自定义标签是如何解析的了,如何解析的详细逻辑则需要看一下DubboBeanDefinitionParser这个类,无非就是解析各个属性,根据不同的class类型注册不同的bean,下面贴了部分代码参考。关于DubboBeanDefinitionParser的加载问题,可以参照spring引入servicebean。
@SuppressWarnings("unchecked")
private static BeanDefinition parse(Element element, ParserContext parserContext, Class<?> beanClass, boolean required) {RootBeanDefinition beanDefinition = new RootBeanDefinition();beanDefinition.setBeanClass(beanClass);beanDefinition.setLazyInit(false);String id = element.getAttribute("id");if (StringUtils.isEmpty(id) && required) {String generatedBeanName = element.getAttribute("name");if (StringUtils.isEmpty(generatedBeanName)) {if (ProtocolConfig.class.equals(beanClass)) {generatedBeanName = "dubbo";} else {generatedBeanName = element.getAttribute("interface");}}if (StringUtils.isEmpty(generatedBeanName)) {generatedBeanName = beanClass.getName();}id = generatedBeanName;int counter = 2;while (parserContext.getRegistry().containsBeanDefinition(id)) {id = generatedBeanName + (counter++);}}if (id != null && id.length() > 0) {if (parserContext.getRegistry().containsBeanDefinition(id)) {throw new IllegalStateException("Duplicate spring bean id " + id);}parserContext.getRegistry().registerBeanDefinition(id, beanDefinition);beanDefinition.getPropertyValues().addPropertyValue("id", id);}if (ProtocolConfig.class.equals(beanClass)) {for (String name : parserContext.getRegistry().getBeanDefinitionNames()) {BeanDefinition definition = parserContext.getRegistry().getBeanDefinition(name);PropertyValue property = definition.getPropertyValues().getPropertyValue("protocol");if (property != null) {Object value = property.getValue();if (value instanceof ProtocolConfig && id.equals(((ProtocolConfig) value).getName())) {definition.getPropertyValues().addPropertyValue("protocol", new RuntimeBeanReference(id));}}}} else if (ServiceBean.class.equals(beanClass)) {String className = element.getAttribute("class");if (className != null && className.length() > 0) {RootBeanDefinition classDefinition = new RootBeanDefinition();classDefinition.setBeanClass(ReflectUtils.forName(className));classDefinition.setLazyInit(false);parseProperties(element.getChildNodes(), classDefinition);beanDefinition.getPropertyValues().addPropertyValue("ref", new BeanDefinitionHolder(classDefinition, id + "Impl"));}} else if (ProviderConfig.class.equals(beanClass)) {parseNested(element, parserContext, ServiceBean.class, true, "service", "provider", id, beanDefinition);} else if (ConsumerConfig.class.equals(beanClass)) {parseNested(element, parserContext, ReferenceBean.class, false, "reference", "consumer", id, beanDefinition);}Set<String> props = new HashSet<String>();ManagedMap parameters = null;// 此处省略很多代码return beanDefinition;
}