整体上按分层进行分包,然后每个包又分API包和具体的方案包,从中提炼出三个需要注意的点
大凡发展的比较好的框架,都遵守微核的理念, Eclipse的微核是OSGi(依赖META-INF/MANIFEST.MF配置), Spring的微核是BeanFactory,Maven的微核是Plexus,Dubbo的微核是SPI(依赖META-INF/services/com.xxx.xxx配置)。通常核心是不应该带有功能性的,而是一个生命周期和集成容器,负责加载、卸载、运行插件模块,这样各功能可以通过相同的方式交互及扩展,并且任何功能都可以被替换。如果做不到微核,至少要平等对待第三方,即原作者能实现的功能,扩展者应该可以通过扩展的方式全部做到,原作者要把自己也当作扩展者,这样才能保证框架的可持续性及由内向外的稳定性。
将一个事件处理流程分派到一组执行对象上,这一组执行对象形成一个链式结构,事件处理在这一组对象上进行传递
框架不应该控制实现类的生命周期,框架最多提供工具类辅助管理,而不是绝对控制,应满足下面的规范
URL作为Dubbo一个公共契约,所有的扩展点都包含URL参数,URL作为上下文信息贯穿整个扩展点设计体系。所有的配置信息都转换成URL的参数,所有的元信息传输都采用URL,所有的接口都可以获取到URL
领域模型划分好处:结构清晰,可直接套用;充血模型,实体域带行为;可变和不可变状态分离,可变状态集中;所有领域线程安全,不需要加锁
Dubbo中的API如ServiceConfig/ReferenceConfig/RpcContext是给使用者使用的,Dubbo中的SPI如Protocol/Transporter/LoadBalance,是给扩展者使用的,API应该是声明式的,描述需要什么,SPI应该是过程式的,描述怎么实现。它们不应该混在一起,使用者不应该看到扩展者写的实现
管道一般适用于组合行为,主功能以截面AOP实现,比如Servlet。派发一般适用于策略行为,主功能以事件Event实现,比如Flux
没有哪个公用的框架可以Cover住所有的需求,不管是Web框架的请求响应流、ORM框架的SQL-Mapping过程,还是Service框架的调用过程,允许外置行为是框架的基本扩展方式,不然如果需要添加安全、日记或者修改分页SQL等不得不hack源代码了
Dubbo中使用全管道设计,框架自身逻辑,均使用截面拦截实现,比如常见于消费端的context/collect/generic/activelimit/monitor/future等链式过滤器,常见于生产端的token/exception/echo/accesslog/trace/executelimit等链式过滤器
拦截器是在切点执行前后生效的,它是干预过程的,会触发非关键行为,而事件是基于状态数据的,会触发状态观察者行为
Reactor模型关注就绪状态,比如可读了就通知我们主动去读,类似Linux epoll,而proactor关心的是完成状态,比如我们指定存放数据的内存地址(Buffer)和读事件,当它读完了就会通知我们,类似Windows IO completion port
Dubbo在关键路径上采用拦截链分离职责,保持界面功能单一,不易出问题。在非关键路径上,采用后置派发,即使派发失败也不会影响主流程运行
开闭原则,对扩展开放,对修改关闭,因为风险往往来自于修改。拥抱变化时应该继承原有类然后重写方法扩展逻辑,而不是修改原来的类
如果现有一个无状态消息发送的场景,后来新增一个会话消息发送需求,如果采用增量式扩展,无状态消息发送原封不动,同步消息发送,在无状态消息基础上加一个 Request/Response 处理,会话消息发送,再加一个 SessionRequest/SessionResponse 处理
传统的C/S模型是一问一答模式,而Dubbo的RPC模型中包括了Proxy/Custer/Protocol, Protocol只负责协议实现,它是不透明的、点对点的,Cluster只负责将集群中多个提供者伪装成一个,Proxy只负责透明化接口,桥接动态代理,整体的架构非常容易扩展
尽可能少的依赖低阶契约,用最少的抽象概念实现功能。当低阶切换实现时,高阶功能可以继续复用
以PHP到Router的request body中的方法名和方法参数作为Router远程调用后端Java服务的入参,最后将远程调用的result返回给PHP端就是兼容Restful服务的高阶泛化调用
文章来源:www.liangsonghua.me
作者介绍:京东资深工程师-梁松华,长期关注稳定性保障、敏捷开发、JAVA高级、微服务架构