1、API和SPI分离
dubbo提供的API是稳定的,如果通过spring配置来暴露和引用服务,甚至接触不到API,不过如果选择通过代码的方式来暴露服务和引用服务,那就需要和ReferenceConfig和ServiceConfig这两个API交互,这两个API背后所依赖的一些组件都是可扩展和可替换的,比如选择以什么样的协议暴露服务(Protocol)、以什么样的方式生成代理(consumer端)和创建invoker(provider端)、用什么样的通信层(Transport),都是可以通过参数配置的,这给了框架开发和维护人员很大的灵活性和施展空间,同时让框架的扩展对用户透明。举个简单的例子,假设有一个框架提供了一个API如下:
public class Action {
void execute();
}
用来获取数据,执行业务计算,最后输出结果。这个API有很多种实现,比如有从DB获取数据的实现,有从文件获取数据的实现,还有输出结果到屏幕的实现和输出结果到DB的实现。如果为每一种实现都创建一个子类,让业务方选择用某一个子类实现自己的业务功能,就是耦合API和SPI的一个例子。如果哪一天框架又新增了几种实现,那么业务方必须替换原有的实现类才能使用新功能,这无疑是一种很差的设计。合理的做法是,将获取数据的方式抽象成一个SPI接口DataInput,将输出结果的方式抽象成另一个接口DataRender,然后为这两个SPI提供多种实现,而Action类将这两个工作代理给这两个SPI接口,业务方始终只和Action交互,至于Action要用SPI的哪一种实现去完成工作,这个由配置项在启动时决定或者运行时动态决定。
这其也符合尽可能使用组合而不是继承的思想。
2、框架需要提供拦截和通知机制
没有任何一种框架可以满足用户全部的需求(哪怕当前满足了,未来还会有新需求),因此框架的设计者都会预留出扩展的余地,dubbo也不例外,除了功能强大的SPI机制,还有另外两种扩展的方式,它们是调用拦截和重要事件的通知机制。
1、调用拦截
ORM框架有sql执行过程的拦截,web框架有请求处理过程的拦截,rpc框架也有调用拦截。d