1:一些设计上的基本常识
(1)API与SPI分离
API:Application Programming Interface 提供给:使用者
SPI:Service Provide Interface 提供给:扩展者
下图一:SPI接口混在API接口中。

下图二:SPI接口合API接口分离

(2)服务域、实体域、会话域分离
实体域:通常是线程安全的,一般指框架或组件的核心领域模型,代表我们要操作的目标本身,比如:spring的bean,dubbo的Service等。
服务域:也是行为域,它是组件的功能集,同时也负责实体域合会话域的生命周期管理。也是线程安全的。比如:spring的ApplicationContext、Dubbo的ServiceManager等。
会话域:会话就是一次交互过程。会话中重要的概念是上下文。上下文通常持有交互过程中的状态变量等。会话对象通常较轻,每次请求都重新创建实例,请求结束后销毁。简而言之:把元信息交由实体域持有,把一次请求中的临时状态由会话域持有,由服务域贯穿整个过程。

(3)在重要的过程上设置拦截接口

(4)重要的状态的变更发送事件并留出监听接口
事件和拦截器的区别:
拦截器是干预过程的,它是过程的一部分,是基于过程行为的。而事件是基于状态数据的,任何行为改变的
相同状态,对事件应该是一致的。???思考一下这句话?挺有意思?

(5)扩展接口职责尽可能单一,具有可组合性
(6)微核插件式,平等对待第三方
啥叫微核理念???Eclipse的微核是OSGi,Spring的微核是BeanFactory,Maven的微核是Plexus。
(7)不要控制外部对象的生命周期
好的办法:框架只使用外部对象,这些对象是怎么创建,怎么销毁,都和框架无关,框架最多提供工具类辅助管理,而不是绝对控制。
(8)可配置一定可编程,并保持友好的CoC约定(Convention over Configuration:惯例优于配置原则,简单点说,就是将一些公认的配置方式和信息作为内部缺省的规则来使用。)
(9)区分命令与查询,明确前置条件与后置条件
尽量遵守:(契约式设计的一部分)
A:有返回值的方法是查询方法,void返回的方法是命令。
B:查询方法通常是幂等性的,也就是n次结果都是一样的。
C:命令是指有副作用的,也就是会修改状态,比如:set某个值,或update某条数据库的记录。如果你的方法既做了修改,又做了删除,如果可能,尽量将其拆分成读写两个方法。
D:每个方法上都尽量前置断言传入参数的合法性,后置断言返回结果的合法性,并文档化。
(10)增量式扩展,而不要扩充原始核心概念
下面紧接着的第二章节细讲。????
2:谈谈扩充式扩展与增量式扩展
很好理解,思考、思考、再思考。
3:配置设计
(1)配置分类
根据配置的用途,大致分为:
A:环境配置,比如:连接数、超时等配置等
B:描述配置,比如:服务接口描述,服务版本等
C:扩展配置,比如:协议扩展,策略扩展等
(2)配置格式
A:环境配置,通常用properties就行。
B:描述配置,用xml就行,或者Annotation,想想为啥?
C:扩展配置,分情况:如果只是策略接口实现类替换,可以考虑properties等结构。如果有复杂的生命周期管理,可能需要xml等配置。有时候扩展会通过注册接口的方式提供。
(3)配置加载
A:dubbo中扩展配置是怎么实现的,配置在项目的META-INF目录下。(采用的思想:Java标准的服务发现机制,即:在jar包的META-INF/services下放置接口类全名文件,内容为每行一个实现类类名。就像jdk中的加密算法扩展、脚本引擎扩展、新的JDBC驱动等,都是采用这种方式。)
(4)可编程配置
配置的可编程性非常必要,不管你以何种方式加载配置文件,都应该提供一个编程的配置方式。
(5)配置缺省值
怎么使用需要注意???
(6)配置一致性
怎么使用需要注意???
(7)配置覆盖
怎么使用需要注意???
(8)配置继承
怎么使用需要注意???
(9)配置向后兼容
怎么使用需要注意???
4:设计实现的健壮性
(1)日志
要有效利用日志这个工具需要注意:
A:严格约定WARN、ERROR级别记录的内容
WARN:表示可以恢复的问题,无需人工介入。
ERROR:表示需要人工介入问题。
B:日志中,尽量多的收集关键信息。
C:同一个或是一类问题不要重复记录多次
(2)界限设置
(3)线程池(ExecutorService)的大小和饱和策略
(4)集合容量
(5)容错-重试-恢复
(6)Dubbo的服务注册中心
(7)服务的消费者
(8)重试延迟策略
相关场景举例子:
A:数据库上的活锁
B:Client重连注册中心
5:防痴呆设计
(1)检查重复的jar包
(2)检查重复的配置文件
(3)检查所有可选配置
(4)异常信息给出解决方案
(5)日志信息包含环境信息
(6)kill之前先dump
6:扩展点重构
(1)第一步,微核心,插件式,平等对待第三方
(2)第二步,每个扩展点只封装一个变化因子,最大化重用
(3)第三步,全管道式设计,框架自身逻辑,均使用截面拦截实现
(4)第四步,最少概念,一致性概念模型
(5)第五步,分层,组合式扩展,而不是泛化式扩展
(6)第六步,整理,梳理关系
网友评论