`
javatar
  • 浏览: 1679519 次
  • 性别: Icon_minigender_1
  • 来自: 杭州699号
社区版块
存档分类
最新评论

Dubbo扩展点重构

阅读更多
转于自己在公司的Blog:
http://pt.alibaba-inc.com/wp/dev_related_1283/dubbo-extension.html

随着服务化的推广,网站对Dubbo服务框架的需求逐渐增多,
Dubbo的现有开发人员能实现的需求有限,很多需求都被delay,
而网站的同学也希望参与进来,加上领域的推动,
所以平台计划将部分项目对公司内部开放,让大家一起来实现,
Dubbo为试点项目之一。

既然要开放,那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,减少概念。

第五步,分层,组合式扩展,而不是泛化式扩展。
原因参见:http://javatar.iteye.com/blog/690845
泛化式扩展指:将扩展点逐渐抽象,取所有功能并集,新加功能总是套入并扩充旧功能的概念。
组合式扩展指:将扩展点正交分解,取所有功能交集,新加功能总是基于旧功能之上实现。
上面的设计,不自觉的就将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核心的一个扩展,设计如下:


第六步,整理,梳理关系。

整理后,设计如下:


------------------------
Dubbo设计分享系列:
配置设计
防痴呆设计
负载均衡扩展接口重构
一些设计上的基本常识
谈谈泛化式扩展与组合式扩展
  • 大小: 118.8 KB
  • 大小: 138 KB
  • 大小: 161.9 KB
  • 大小: 235.1 KB
分享到:
评论
3 楼 xiaxilin 2016-03-09  
mark!!!!!!!!!!!!
2 楼 mordecai 2014-10-31  
好文,感谢分享
1 楼 xiaomei1029 2013-08-22  
最近公司让把java的Dubbo框架,变成.net框架。请问我该怎么实现啊

相关推荐

    xdubbo:xdubbo麦克风核心

    XDubbo Mic-Corexdubbo从扩展点也叫微内核设计着手思考如何重构,并配合本人设计的秒杀分布式系统架构演进进行实际超高并发场景压测重构的驱动思想是新兴springCloud,service mesh框架与实际行业特性之间存在哪些...

    XMall分布式电商购物商城-其他

    单点登录系统:为多个系统之间提供用户登录凭证以及查询登录用户的信息 XMall v1.1更新日志(需更新前后台代码及SQL) 接入自己开源的XPay个人免签收款支付系统 更新Dubbo(2.6.1)、ES(6.2.3)等依赖版本 消ES需在页面中...

    抽奖系统设计方案.pdf

     4.2 重构关键技法 重构关键技法 静态 -> 动态 早绑定 -> 晚绑定 继承 -> 组合 编译时依赖 -> 运⾏时依赖 紧耦合 -> 松耦合 4.3 本项⽬中运⽤的设计模式 本项⽬中运⽤的设计模式 对象创建过程中使⽤new,new依赖...

    java开源包1

    同时保持蒸提供全面的支持,无缝集成的IDE(语法着色,代码导航,重构等)的语法和操作代码完全分离。最大限度地减少时间和费用开发自定义的DSL(领域特定语言在Java)要求。 日志服务器 Apache Flume.tar Flume 是...

    java开源包11

    同时保持蒸提供全面的支持,无缝集成的IDE(语法着色,代码导航,重构等)的语法和操作代码完全分离。最大限度地减少时间和费用开发自定义的DSL(领域特定语言在Java)要求。 日志服务器 Apache Flume.tar Flume 是...

    java开源包2

    同时保持蒸提供全面的支持,无缝集成的IDE(语法着色,代码导航,重构等)的语法和操作代码完全分离。最大限度地减少时间和费用开发自定义的DSL(领域特定语言在Java)要求。 日志服务器 Apache Flume.tar Flume 是...

    java开源包3

    同时保持蒸提供全面的支持,无缝集成的IDE(语法着色,代码导航,重构等)的语法和操作代码完全分离。最大限度地减少时间和费用开发自定义的DSL(领域特定语言在Java)要求。 日志服务器 Apache Flume.tar Flume 是...

    java开源包6

    同时保持蒸提供全面的支持,无缝集成的IDE(语法着色,代码导航,重构等)的语法和操作代码完全分离。最大限度地减少时间和费用开发自定义的DSL(领域特定语言在Java)要求。 日志服务器 Apache Flume.tar Flume 是...

    java开源包5

    同时保持蒸提供全面的支持,无缝集成的IDE(语法着色,代码导航,重构等)的语法和操作代码完全分离。最大限度地减少时间和费用开发自定义的DSL(领域特定语言在Java)要求。 日志服务器 Apache Flume.tar Flume 是...

    java开源包10

    同时保持蒸提供全面的支持,无缝集成的IDE(语法着色,代码导航,重构等)的语法和操作代码完全分离。最大限度地减少时间和费用开发自定义的DSL(领域特定语言在Java)要求。 日志服务器 Apache Flume.tar Flume 是...

    java开源包4

    同时保持蒸提供全面的支持,无缝集成的IDE(语法着色,代码导航,重构等)的语法和操作代码完全分离。最大限度地减少时间和费用开发自定义的DSL(领域特定语言在Java)要求。 日志服务器 Apache Flume.tar Flume 是...

    java开源包8

    同时保持蒸提供全面的支持,无缝集成的IDE(语法着色,代码导航,重构等)的语法和操作代码完全分离。最大限度地减少时间和费用开发自定义的DSL(领域特定语言在Java)要求。 日志服务器 Apache Flume.tar Flume 是...

    java开源包7

    同时保持蒸提供全面的支持,无缝集成的IDE(语法着色,代码导航,重构等)的语法和操作代码完全分离。最大限度地减少时间和费用开发自定义的DSL(领域特定语言在Java)要求。 日志服务器 Apache Flume.tar Flume 是...

    java开源包9

    同时保持蒸提供全面的支持,无缝集成的IDE(语法着色,代码导航,重构等)的语法和操作代码完全分离。最大限度地减少时间和费用开发自定义的DSL(领域特定语言在Java)要求。 日志服务器 Apache Flume.tar Flume 是...

    java开源包101

    同时保持蒸提供全面的支持,无缝集成的IDE(语法着色,代码导航,重构等)的语法和操作代码完全分离。最大限度地减少时间和费用开发自定义的DSL(领域特定语言在Java)要求。 日志服务器 Apache Flume.tar Flume 是...

    Java资源包01

    同时保持蒸提供全面的支持,无缝集成的IDE(语法着色,代码导航,重构等)的语法和操作代码完全分离。最大限度地减少时间和费用开发自定义的DSL(领域特定语言在Java)要求。 日志服务器 Apache Flume.tar Flume 是...

    JAVA上百实例源码以及开源项目

    1个目标文件,JNDI的使用例子,有源代码,可以下载参考,JNDI的使用,初始化Context,它是连接JNDI树的起始点,查找你要的对象,打印找到的对象,关闭Context…… ftp文件传输 2个目标文件,FTP的目标是:(1)提高...

    JAVA上百实例源码以及开源项目源代码

    1个目标文件,JNDI的使用例子,有源代码,可以下载参考,JNDI的使用,初始化Context,它是连接JNDI树的起始点,查找你要的对象,打印找到的对象,关闭Context…… ftp文件传输 2个目标文件,FTP的目标是:(1)提高...

Global site tag (gtag.js) - Google Analytics