Dubbo为何凭借它崭露头角,开源框架的这一点如此关键?

摘要:Hola,我是 yes。 经过了 RPC 核心和 Dubbo 微内核两篇文章后,今天终于要稍稍深入一波 Dubbo 了。 作为一个通用的 RPC 框架,性能是很重要的一环,而易用性和扩展性也极为重要。 简单地、无侵入式地扩展和定制 RPC
Hola,我是 yes。 经过了 RPC 核心和 Dubbo 微内核两篇文章后,今天终于要稍稍深入一波 Dubbo 了。 作为一个通用的 RPC 框架,性能是很重要的一环,而易用性和扩展性也极为重要。 简单地、无侵入式地扩展和定制 RPC 各阶段功能是很多团队的述求,Dubbo 就满足了这些需求。 它通过微内核设计和 SPI 扩展,使得一些有特殊需求的业务团队可以在 Dubbo 中实现自己的扩展,而不需要修改源码。 Dubbo 的成功离不开这样的设计,今天咱们就来盘一盘 Dubbo 是如何实现无侵入扩展的,其间还会看到 Dubbo 的 IOC 和 AOP。 还有先打个预防针,今天的内容代码有点多的,毕竟想要深入剖析,源码必不可少,刚好也顺带提一下看源码的小技巧。 所以建议电脑上看,更加清晰和舒适。 还有如果有没看过源码的同学,来紧跟 Dubbo 这个系列吧,到时候再也不怕被面试官问看过源码没了。 SPI Dubbo 就是利用 SPI (Service Provider Interface)来实现扩展机制的。 这个 SPI 想必你们都很熟悉,在大学写数据库大作业的时候就碰到了,访问数据库需要用到 java.sql.Driver。 市面上的数据库五花八门,每个数据库厂商都有自己的实现,所以肯定需要定制一个接口,这样我们面向接口编程即可。 而具体的实现则可以通过配置来加载,JDK SPI 这时候就派上用场了。 其实一点都不神奇,就是约定一个地方,加载的时候就去那个地方找实现类。 约定一个地方直白点说就是代码里面写死了一个目录,这个目录就是 META-INF/services/。 然后在这个目录下创建一个文件,用接口全限定名来命名,文件内容就是实现类的全限定名。 到时候要实现类就根据接口名来这里找,然后实例化就行了。 挺简单的吧,这就是 JDK SPI,但是它不满足 Dubbo 的需求。 因为 Dubbo 把自身的一些实现也剥离出来成为扩展,而这些实现还是有点多的,也不需要全部用上。 如果用 JDK SPI 会把配置文件里面的类全部加载,这就导致资源的浪费。用的时候还需要遍历过去才能找到对应的实现。 所以 Dubbo 就在 JDK SPI 的基础上实现了个 Dubbo 的 SPI,可以根据指定的名称按需加载实现类,比如拿 Cluster 来说就有这么多实现类。 约定的地方改了一下,一共有三个目录。 META-INF/dubbo/internal/ :这里是存放 Dubbo 内部使用的 SPI 配置文件。 META-INF/dubbo/ :这里是存放用户自定义 SPI 配置文件。 META-INF/services/:兼容 JDK SPI 然后文件里面的内容是key=value形式,这样就可以根据 key 找到对应的实现类。 然后在注解上可以配置默认的 key 来选择默认的实现类,比如 Cluster 默认的实现是 failover。 也可以通过 URL 参数来选择实现类。 还有像 JDK SPI 扩展点加载失败的话,连扩展点名称都拿不到,到时候报错也不知道哪里出问题。 而 Dubbo SPI 则不会吃了错误,并且还提供了扩展点的自动注入和 AOP 功能。 大致了解了 Dubbo SPI 之后,我们再来深入看看实现细节。 Dubbo SPI 实现细节 Dubbo SPI 的核心实现在 ExtensionLoader 中,它负责扩展点的加载和生命周期的维护,类似 JDK SPI 的 ServiceLoader。 这里要先提一点看源码的小技巧了。 开源框架都会有单元测试,而单元测试里面就会有我们看源码时候想要的各种功能实现,我们就可以从单元测试入手得知一些功能的划分,然后断点调试逐渐深入。 比如今天文章的 ExtensionLoader ,它在 dubbo-common 模块中,咱们就进入 test 来看看它测试用例怎么写的。 当然除了通过文件夹来找,直接用文件名搜也行。 找到了就好办了,数据都是造好的,找到你想要调试的方法,断点一设,箭头一点,这不就美滋滋了吗? 好了,小技巧分享完毕,回到 ExtensionLoader,我们简单点就用 Dubbo 单元测试的数据来看看实现。 有个叫 SimpleExt 的类,有三个实现,默认的实现是 impl1。 再来看看 SPI 配置文件的内容,可以看到为了测试还故意写了一些空格在配置文件中。 然后现在如果要找 impl2 这个实现,通过以下代码调用即可。
阅读全文