dubbo的扩展点重构
可扩展设计是框架要重点考虑的设计,因为它直接影响到框架的稳定性和功能的扩展,Dubbo扩展点重构、它在扩展性设计上踩过的坑,值得框架设计者借鉴学习。
第一步,微核心,插件式,平等对待第三方
即然要扩展,扩展点的加载方式,首先要统一,微核心+插件式,是比较能达到 OCP 原则的思路。
由一个插件生命周期管理容器,构成微核心,核心不包括任何功能,这样可以确保所有功能都能被替换,并且,框架作者能做到的功能,扩展者也一定要能做到,以保证平等对待第三方,所以,框架自身的功能也要用插件的方式实现,不能有任何硬编码。
通常微核心都会采用 Factory、IoC、OSGi 等方式管理插件生命周期。考虑 Dubbo 的适用面,不想强依赖 Spring 等 IoC 容器。自已造一个小的 IoC 容器,也觉得有点过度设计,所以打算采用最简单的 Factory 方式管理插件。
最终决定采用的是 JDK 标准的 SPI 扩展机制,参见:
java.util.ServiceLoader,也就是扩展者在 jar 包的META-INF/services/目录下放置与接口同名的文本文件,内容为接口实现类名,多个实现类名用换行符分隔。比如,需要扩展 Dubbo 的协议,只需在 xxx.jar 中放置文件:META-INF/services/com.alibaba.dubbo.rpc.Protocol,内容为com.alibaba.xxx.XxxProtocol。Dubbo 通过 ServiceLoader 扫描到所有 Protocol 实现。并约定所有插件,都必须标注:
@Extension("name"),作为加载后的标识性名称,用于配置选择。第二步,每个扩展点只封装一个变化因子,最大化复用
每个扩展点的实现者,往往都只是关心一件事,现在的扩展点,并没有完全分离。比如:Failover, Route, LoadBalance, Directory 没有完全分开,全由 RoutingInvokerGroup 写死了。
再比如,协议扩展,扩展者可能只是想替换序列化方式,或者只替换传输方式,并且 Remoting 和 Http 也能复用序列化等实现。这样,需为传输方式,客户端实现,服务器端实现,协议头解析,数据序列化,都留出不同扩展点。
拆分后,设计如下:
第三步,全管道式设计,框架自身逻辑,均使用截面拦截实现
现在很多的逻辑,都是放在基类中实现,然后通过模板方法回调子类的实现,包括:local, mock, generic, echo, token, accesslog, monitor, count, limit 等等,可以全部拆分使用 Filter 实现,每个功能都是调用链上的一环。 比如:(基类模板方法)
public abstract AbstractInvoker implements Invoker { public Result invoke(Invocation inv) throws RpcException {
// 伪代码
active ++;
if (active > max)
wait(); doInvoke(inv); active --;
notify();
} protected abstract Result doInvoke(Invocation inv) throws RpcException }
改成:(链式过滤器)
public abstract LimitFilter implements Filter { public Result invoke(Invoker chain, Invocation inv) throws RpcException {
// 伪代码
active ++;
if (active > max)
wait(); chain.invoke(inv); active --;
notify();
} }
第四步,最少概念,一致性概念模型
保持尽可能少的概念,有助于理解,对于开放的系统尤其重要。另外,各接口都使用一致的概念模型,能相互指引,并减少模型转换,
比如,Invoker 的方法签名为:
Result invoke(Invocation invocation) throws RpcException;
而 Exporter 的方法签名为:
Object invoke(Method method, Object[] args) throws Throwable;
但它们的作用是一样的,只是一个在客户端,一个在服务器端,却采用了不一样的模型类。
再比如,URL 以字符串传递,不停的解析和拼装,没有一个 URL 模型类, 而 URL 的参数,却时而 Map, 时而 Parameters 类包装,
export(String url)
createExporter(String host, int port, Parameters params);
使用一致模型:
export(URL url)
createExporter(URL url);
再比如,现有的:Invoker, Exporter, InvocationHandler, FilterChain 其实都是 invoke 行为的不同阶段,完全可以抽象掉,统一为 Invoker,减少概念。
第五步,分层,组合式扩展,而不是泛化式扩展
原因参见:谈谈扩充式扩展与增量式扩展。
泛化式扩展指:将扩展点逐渐抽象,取所有功能并集,新加功能总是套入并扩充旧功能的概念。
组合式扩展指:将扩展点正交分解,取所有功能交集,新加功能总是基于旧功能之上实现。
上面的设计,不自觉的就将 Dubbo 现有功能都当成了核心功能。上面的概念包含了 Dubbo 现有 RPC 的所有功能,包括:Proxy, Router, Failover, LoadBalance, Subscriber, Publisher, Invoker, Exporter, Filter 等, 但这些都是核心吗?踢掉哪些,RPC 一样可以 Run?而哪些又是不能踢掉的?基于这样考虑,可以将 RPC 分解成两个层次,只是 Protocol 和 Invoker 才是 RPC 的核心。其它,包括 Router, Failover, Loadbalance, Subscriber, Publisher 都不核心,而是 Routing。所以,将 Routing 作为 Rpc 核心的一个扩展,设计如下:
第六步,整理,梳理关系
整理后,设计如下:
http://dubbo.apache.org/books/dubbo-dev-book/principals/extension.html

dubbo的扩展点重构的更多相关文章
- 理解 Dubbo SPI 扩展机制
写在前面 最近接触了 gRPC 体会到虽然众多 RPC 框架各有各的特点但是他们提供的特性和功能有很多的相似之处 , 这就说明他们面对同样的分布式系统带来的问题.从 2016 年左右开始接触到 dub ...
- [转] 理解 Dubbo SPI 扩展机制
写在前面 最近接触了 gRPC 体会到虽然众多 RPC 框架各有各的特点但是他们提供的特性和功能有很多的相似之处 , 这就说明他们面对同样的分布式系统带来的问题.从 2016 年左右开始接触到 dub ...
- 聊聊Dubbo - Dubbo可扩展机制实战
1. Dubbo的扩展机制 在Dubbo的官网上,Dubbo描述自己是一个高性能的RPC框架.今天我想聊聊Dubbo的另一个很棒的特性, 就是它的可扩展性. 如同罗马不是一天建成的,任何系统都一定是从 ...
- C# 利用范型与扩展方法重构代码
在一些C#代码中常常可以看到 //An Simple Example By Ray Linn class CarCollection :ICollection { IList list; public ...
- Dubbo/jupiterSPI 扩展引用
ProviderTenantService providerResourceService = ExtensionLoader.getExtension(ProviderTenantService.c ...
- Dubbo源码分析系列---扩展点加载
扩展点配置: 约定: 在扩展类的jar包内,放置扩展点配置文件:META-INF/dubbo/接口全限定名,内容为:配置名=扩展实现类全限定名,多个实现类用换行符分隔.(摘自dubbo文档) 示例: ...
- Dubbo中SPI扩展机制解析
dubbo的SPI机制类似与Java的SPI,Java的SPI会一次性的实例化所有扩展点的实现,有点显得浪费资源. dubbo的扩展机制可以方便的获取某一个想要的扩展实现,每个实现都有自己的name, ...
- Dubbo死磕之扩展点加载ExetnsionLoader
dubbo的SPI机制与JDK的SPI机制对比 dubbo一款阿里一款开源的RPC框架,他本身是一款非常复杂的系统,我们主要针对里边的一些核心点来展开分析,其中duboo里的一种核心机制 ...
- Dubbo学习笔记6:Dubbo增强SPI与SPI中扩展点自动包装的实现原理
在Dubbo整体架构分析中介绍了Dubbo中除了Service和Config层为API外,其他各层均为SPI,为SPI意味着下面各层都是组件化可以被替换的,也就是扩展性比较强,这也是Dubbo比较好的 ...
随机推荐
- python升级或者其他原因把yum搞坏了
第一个命令查询出来,原本是安装的啥版本 rpm -qa | grep python- | grep 2.6 然后执行下一个命令,就可以安装原本的python版本了,注意链接要换成你对应的那个版本 rp ...
- 小鬼PSer
我是小鬼PSer,主要修图和做网站的,有需要可以call QQ:1805843351 微信:1805843351
- mongodb的mongod.lock文件及oplog文件
在mongodb的启动时,在数据目录下,会生成一个mongod.lock文件.如果在正常退出时,会清除这个mongod.lock文件,若要是异常退出,在下次启动的时候,会禁止启动,从而保留一份干净的一 ...
- 申请edu邮箱
https://blog.csdn.net/w305607610/article/details/86771593 手把手教你申请CCC(City Colleges of Chicago)教育邮箱 台 ...
- 五个知识体系之-SQL学习-第一天
1. 创建数据库 CREATE DATABASE test1; 2. 删除数据库 DROP DATABASE test1; 3. 创建表 CREATE TABLE tabname (userid BI ...
- Latex 4: WinEdt 10试用时间限制的破解+注册码激活
方法1:我发现这个方法1,现在(2018.06.05)在winedt 10.2上已经不能用了,在低版本(10.1及以下版本)上还可以用,所以如果方法1不行,请看方法2. WinEdt 是目前我发现最好 ...
- Docker与虚拟化
核心知识点: 1.虚拟化的定义?虚拟化的核心和目标? 2.虚拟化的分类?Docker属于那种虚拟化? 3.Docker与传统虚拟化的区别?docker是直接在操作系统上实现虚拟化,直接复用本地操作系统 ...
- DLL中导出ANSI和UNICODE函数
模仿window中的DLL导出ANSI和UNICODE版本的函数,使用UNICODE宏来控制使用哪个版本: 在函数实际的执行代码UNICODE版本中,在ANSI函数的版本中只做参数的转换,及ANSI字 ...
- redis的安装与类型
redis Redis 是一个开源(BSD许可)的,内存中的数据结构存储系统,它可以用作数据库.缓存和消息中间件 源码安装 redis , 编译安装 为何用源码安装,不用yum安装, 编译安装的优势 ...
- ubuntu16.04下安装wordpress
安装过程 http://blog.topspeedsnail.com/archives/4635 http://blog.topspeedsnail.com/archives/4646 碰到的问题 1 ...


