背景

在 Dubbo 中,可以使用 XML 配置相关信息,也可以用来引入服务或者导出服务。配置完成,启动工程,Spring 会读取配置文件,生成注入 相关 Bean。那 Dubbo 如何实现自定义 XML 被 Spring 加载读取?

Spring XML Schema 扩展机制。从 Spring 2.0 开始,Spring 开始提供了一种基于 XML Schema 格式扩展机制,用于定义和配置 bean。

Spring XML Schema 扩展机制

实现 Spring XML Schema 扩展,其实非常简单,只需要完成下面四步。

  1. 创建 XML Schema 文件,由于该文件后缀名为 xsd,下面称为 XSD 文件。
  2. 编写实现一个或多个 BeanDefinitionParser
  3. 编写NamespaceHandler实现类。
  4. 注册 NamespaceHandler 以及 XSD 文件。

我们按照以上步骤,最终完整 Spring 解析如下配置。

<?xml version="1.0" encoding="UTF-8"?><beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xmlns:demo="http://www.test.com/demo"xsi:schemaLocation="http://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.test.com/demo http://www.test.com/demo/demo.xsd"><demo:application name="test" id="test"/>
</beans>
复制代码

创建 XSD 文件

XSD 文件,主要用来定义 XML 格式,用来验证 XML 合法性。在 IDE 中,导入 XSD 文件,编辑 XML 文件可以获得相关提示。

下面我们生成一个 XSD 文件。

<?xml version="1.0" encoding="UTF-8"?>
<xsd:schema xmlns="http://www.test.com/demo"xmlns:xsd="http://www.w3.org/2001/XMLSchema"xmlns:beans="http://www.springframework.org/schema/beans"targetNamespace="http://www.test.com/demo"elementFormDefault="qualified"attributeFormDefault="unqualified"><xsd:import namespace="http://www.springframework.org/schema/beans"/><xsd:element name="application"><xsd:complexType><xsd:complexContent><xsd:extension base="beans:identifiedType"><xsd:attribute name="name" type="xsd:string" use="required"/></xsd:extension></xsd:complexContent></xsd:complexType></xsd:element></xsd:schema>
复制代码

上面 XSD 文件中 www.test.com/demo 为自定义命名空间地址,下面将会使用到。

实现 BeanDefinitionParser

这里实现 BeanDefinitionParser,真正解析 XML 动作在这里完成。

由于上面的例子比较简单,我们可以直接继承 Spring 提供的抽象类 AbstractSingleBeanDefinitionParser,然后实现相关方法就可以了。

public class DemoBeanDefinitionParser extends AbstractSingleBeanDefinitionParser {/*** 返回最会需要注入 Spring Bean 的类型* @param element* @return*/@Overrideprotected Class<?> getBeanClass(Element element) {return DemoApplication.class;}/**** 这个方法完成真正解析动作* @param element* @param builder*/@Overrideprotected void doParse(Element element, BeanDefinitionBuilder builder) {String name=element.getAttribute("name");builder.addPropertyValue("name",name);}
}复制代码

当然也可以直接实现 BeanDefinitionParser,这样更加灵活,但是这样相比于上面这个就比较复杂了。

public class BeanApplicationDefinitionParser implements BeanDefinitionParser {@Overridepublic BeanDefinition parse(Element element, ParserContext parserContext) {String name=element.getAttribute("name");// Bean 定义,最后根据这个生产 BeanRootBeanDefinition rootBeanDefinition=new RootBeanDefinition();rootBeanDefinition.setBeanClass(DemoApplication.class);rootBeanDefinition.setLazyInit(false);// 添加解析的属性rootBeanDefinition.getPropertyValues().add("name",name);// 将生成的 BeanDefinition 注册,少了这一步将会导致最后生成 Bean 时报错parserContext.getRegistry().registerBeanDefinition("application",rootBeanDefinition);return rootBeanDefinition;}
}
复制代码

实现 NamespaceHandler

这一步实现 NamespaceHandler,开发者自定义 NamespaceHandler 只要继承 NamespaceHandlerSupport 抽象类,实现 init 方法。在这个方法中注册上面一步实现 BeanDefinitionParser

public class DemoNameSpaceHandler extends NamespaceHandlerSupport {@Overridepublic void init() {// elementName 为命名空间registerBeanDefinitionParser("application",new BeanApplicationDefinitionParser());}
}
复制代码

注册 XSD 以及 NamespaceHandler

这一步我们需要在 META-INF 中生成两个配置文件,分别为 spring.handlersspring.schemas

spring.schemas 指定 XSD 文件路径。

http\://www.test.com/demo/demo.xsd=com/spring/learning/xml/schemas/autoring/leanrn/demo.xsd
复制代码

spring.handlers 指定 NamespaceHandler 完整类名,既包含前面的包名。

这里需要注意的是 需要进行转义

测试运行

首先我们生产 Spring XML 配置文件。

<?xml version="1.0" encoding="UTF-8"?><beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xmlns:demo="http://www.test.com/demo"xsi:schemaLocation="http://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.test.com/demo http://www.test.com/demo/demo.xsd"><demo:application name="test" id="test"/>
</beans>
复制代码

这里需要注意需要使用 XSD 文件中定义 http://www.test.com/demo

接着我们使用 SpringBoot ,导入 XML 文件,然后运行。

@SpringBootApplication
@ImportResource(locations = {"classpath:applicationContext.xml"})
public class XmlSchemaApplication {public static void main(String[] args) {ConfigurableApplicationContext applicationContext = SpringApplication.run(XmlSchemaApplication.class, args);DemoApplication demoApplication=applicationContext.getBean(DemoApplication.class);System.out.println("application name is "+demoApplication.getName());}
}
复制代码

输出结果为:

application name is test

Spring XML 扩展机制源码研究

这里我们主要研究自定义 XML 扩展文件如何被 Spring 加载。

Spring 启动过程中会通过 BeanDefinitionDocumentReader 读取 beans 标签里面所有配置,这个过程将会通过 BeanDefinitionParserDelegate#parseCustomElement 解析自定义元素。

上面解析过程可以获得自定义 NamespaceHandler,然后调用 parse 方法解析。

接着我们查看 NamespaceHandlerResolver#resolve 方法,查看如何获取自定义 NamespaceHandler

在这个方法中,主要是从 handlerMappings 缓存中获取 NamespaceHandler。而该缓存来源于 getHandlerMappings 方法,这个方法将会加载我们上面自定义 spring.handlers 文件。

看完 Spring 加载 NamespaceHandler 过程,下面我们查看最重要 BeanDefinition 如何生成。

上面已经讲到 Spring 会使用 NamespaceHandler.parse 解析,由于我们继承了 NamespaceHandlerSupport,查看里面具体实现。

获取到 BeanDefinition 会将其注册到容器中,然后会通过 BeanDefinition生成 Bean。这个生成过程不属于本章节内容,所以不再概述,感兴趣同学可以自行搜索。

Dubbo XML Schema 扩展实现

最后我们查看 Dubbo XML Schema 扩展如何实现。

可以看到 Dubbo XML Schema 扩展刚好对应 Spring 四个标准的步骤。

总结

最后用一张图片总结全文内容。

帮助文档

xsd-custom-registration
Spring中的XML schema扩展机制

转载于:https://juejin.im/post/5d06018b518825276a286a3d

缘起 Dubbo ,讲讲 Spring XML Schema 扩展机制相关推荐

  1. 【JEECG Dubbo专题】Dubbo+Zookeeper+Spring整合应用篇-Dubbo基于Zookeeper实现分布式服务(二)

    Dubbo与Zookeeper.Spring整合使用 Dubbo采用全Spring配置方式,透明化接入应用,对应用没有任何API侵入,只需用Spring加载Dubbo的配置即可,Dubbo基于Spri ...

  2. Dubbo源码分析(一)Dubbo与Spring集成实例

    前言 Apache Dubbo (incubating) |ˈdʌbəʊ| 是一款高性能.轻量级的开源Java RPC框架,它提供了三大核心能力:面向接口的远程方法调用,智能容错和负载均衡,以及服务自 ...

  3. dubbo源码分析系列(1)扩展机制的实现

    1 系列目录 dubbo源码分析系列(1)扩展机制的实现 dubbo源码分析系列(2)服务的发布 dubbo源码分析系列(3)服务的引用 dubbo源码分析系列(4)dubbo通信设计 2 SPI扩展 ...

  4. JDK/Dubbo/Spring 三种 SPI 机制,谁更好?

    点击关注公众号,Java干货及时送达 来源:juejin.cn/post/6950266942875779108 SPI 全称为 Service Provider Interface,是一种服务发现机 ...

  5. JDK/Dubbo/Spring 三种 SPI 机制,谁更好呢?

    JDK/Dubbo/Spring 三种 SPI 机制,谁更好? SPI 全称为 Service Provider Interface,是一种服务发现机制.SPI 的本质是将接口实现类的全限定名配置在文 ...

  6. Dubbo源码分析系列之-深入Dubbo扩展机制

    导语:   在之前的博客中分析过Java的SPI机制,其实Dubbo的扩展点加载机制也是从JDK表中的SPI(Service Provider Interface)机制中开发而来,只不过在原生的基础上 ...

  7. Spring 的微内核与FactoryBean扩展机制--转载

    作者:江南白衣 原文地址: http://www.blogjava.net/calvin/archive/2005/08/30/11099.html http://www.blogjava.net/c ...

  8. 聊聊Dubbo - Dubbo可扩展机制源码解析

    2019独角兽企业重金招聘Python工程师标准>>> 摘要: 在Dubbo可扩展机制实战中,我们了解了Dubbo扩展机制的一些概念,初探了Dubbo中LoadBalance的实现, ...

  9. SpringBoot解耦的扩展机制 Spring Factories介绍及使用

    一.什么是 SPI机制 Spring Boot中有一种非常解耦的扩展机制:Spring Factories.这种扩展机制实际上是仿照Java中的SPI扩展机制来实现的.SPI的全名为Service P ...

最新文章

  1. 懂语言者得天下:NLP凭什么被称为人工智能的掌上明珠?
  2. 互联网天生本质与产业大局的开始
  3. 周源:知乎的未来是什么
  4. ios程序内发送邮件的代码
  5. 《剑指offer》给定一颗二叉搜索树,请找出其中的第k大的结点。
  6. 面试官系统精讲Java源码及大厂真题 - 31 AbstractQueuedSynchronizer 源码解析(下)
  7. selenium webdriver 实现Canvas画布自动化测试
  8. python request处理_python requests异常处理
  9. 多项式辗转相除法求最大公约数_多项式的一些性质
  10. Apache Struts 修复 OGNL 技术中可能存在的 RCE 缺陷
  11. 2018南华大学计算机学院,南华大学2019年排名第214位 较2018年下降32名
  12. [转载] Python|range函数用法完全解读
  13. 计算机二级考试题库 操作题,2016计算机二级考试题库:《C++》基本操作题练习...
  14. 泰坦尼克号幸存者逻辑回归预测
  15. vi下Makefile的自动生成
  16. 浙江工商大学计算机专业考研分数,浙江工商大学2021考研分数线已公布
  17. 美国三大航空公司均取消国内航班改签费
  18. 一家图灵奖得主背书创企的陨落,暴露了AI弱国“恒弱”的困境?
  19. 笔记本电流声解决方法
  20. 电子电气架构——基于车载控制器刷写的反思

热门文章

  1. TestNG之注解的生命周期
  2. 智能化网络管理 为企业信息化保驾护航
  3. 关于H3C iNode防代理功能会将pplive等软件检测为代理而下线问题的解决方法
  4. 网络上经典的DOS小命令
  5. 【原】关于ActiveX插件小项目总结
  6. 有了这些经典书籍+配套实验环境上线,还有什么借口说学不好编程?
  7. Go语言入门指南,带你轻松学Go
  8. 腾达fh365虚拟服务器,腾达(Tenda)FH365路由器怎么设置?
  9. 怎么写脚本_直播脚本怎么写|请收下这份攻略
  10. 索引使用原则-列的离散(sàn)度