本文已参与「新人创作礼」活动,一起开启掘金创作之路。
由于没有在实际应用中实施,存在的问题没有暴露,方案仅供参考
目录
disconf-client模块梳理
disconf-client优点
disconf-client问题整理
disconf-client重构设计
1.disconf-client模块梳理
1.1 firstScan
- 客户端总入口DisconfMgr.start
- 根据扫描路径列表scanPackageList开始第一次扫描firstScan
- 初始化init,加载DisClientSysConfig配置:disconf_sys.properties,校验系统配置,加载DisClientConfig配置:disconf.properties,校验客户端配置
- 注册中心工厂RegistryFactory创建spring注册中心SpringRegistry
- 扫描器工厂ScanFactory创建扫描器ScanMgrImpl
- 扫描器第一次扫描指定的包路径列表scanPackageList
- 扫描基本信息scanBasicInfo返回scanModel,扫描静态注解策略ReflectionScanStatic开始扫描路径列表,根据路径扫描路径下的class类型的注解,属性的注解,方法的注解,方法/构造函数和索引参数、返回类型和参数注释,将扫描的DisconfFile、DisconfFileItem、DisconfItem、DisconfActiveBackupService、DisconfUpdateService注解的class以及IDisconfUpdatePipeline接口的子类绑定至scanModel
- 分析扫描后的scanModel analysis,将DisconfFile注解的class,为每个class创建一个方法集合存储同一个class下的DisconfFileItem注解的方法
- 遍历静态扫描器工厂中的实现StaticScannerMgrFactory:StaticScannerFileMgrImpl、StaticScannerItemMgrImpl、StaticScannerNonAnnotationFileMgrImpl,执行扫描数据入仓库scanData2Store,排除忽略的key:exclude
- 扫描数据入库,getDisconfFiles将DisconfFile的class与其对应的DisconfFileItem方法集合封装为DisconfCenterFile返回,从DisconfStoreProcessorFactory工厂中获取DisconfStoreFileProcessorImpl实现进行批量添加配置,其实就是将配置文件缓存至DisconfCenterStore的disconfFileMap
- 从DisconfCore工厂DisconfCoreFactory中获取实现DisconfCoreMgrImpl,从Fetcher工厂获取FetcherMgrImpl实现,如果开启了disconf则同时添加zk的Watcher WatchMgrImpl,返回DisconfCoreMgrImpl实现,并向处理列表中添加DisconfFileCoreProcessorImpl、DisconfItemCoreProcessorImpl实现
- DisconfCoreMgr处理process即:遍历调用处理列表中的实现
- DisconfFileCoreProcessorImpl.processAllItems
- 从DisconfStoreFileProcessorImpl中获取所有配置Key列表,即从DisconfCenterStore仓库中心中获取confFileMap的keyset,也就是DisconfFile注解的filename属性,processOneItem处理filename,获取根据fileName获取confFileMap中的DisconfCenterFile,
- updateOneConfFile更新一个配置文件至本地,下载配置文件至本地,将配置文件注册至中心仓库,即confFileMap中的DisconfCenterFile对应的fileItem配置集合,
- 如果开启了非注解方式注入,并且支持properties则进行reload(遍历所有reloadBean执行,重复加载):ReloadConfigurationMonitor.reload(),直接将fileData绑定至additionalKeyMaps
- watchPath监控路径,将filename创建zk目录节点,将配置以json串格式注册至目录中
- DisconfItemCoreProcessorImpl.processAllItems,代码与file雷同,只是没有filedata以null的形式传入
1.2 secondScan
- 第二遍扫描secondScan其实主要处理扫描的回调服务绑定
- scanUpdateCallbacks扫描更新回调服务
- analysis4DisconfUpdate根据第一遍扫描的ScanModel创建倒排索引(key:配置的key,values:回调服务)
- processItems添加Item类型的倒排索引,DisconfUpdateService注解的itemKeys指定的keys作为反向索引的key
- processFiles添加file类型的倒排索引,DisconfUpdateService注解的classes的Disconf注解以及confFileKeys指定的keys作为反向索引的key
- transformUpdateService向配置中心注册更新回调服务的管道DisconfCenterStore.iDisconfUpdatePipeline
- 将配置注入实例inject2DisconfInstance
非注解配置文件ReloadablePropertiesFactoryBean
- setLocations设置可重加载配置文件
- 遍历文件,将文件注册至disconf,使用StaticScannerNonAnnotationFileMgrImpl实现将远程配置文件下载至本地并注册
- 将文件注册至spring管理支持占位符替换
2.disconf-client优点
- 分布式,上手简单,代码量不多
- 功能健全,性能优于diamand
- 文档整齐健全
- 拥有较广的用户当然也有较多的博客文档
3.disconf-client问题整理
- 社区不活跃
- DisconfFile与DisconfFileItem父子关系,每次匹配都要遍历所有的DisconfFileItem然后获取其所在的class与DisconfFile的所在class进行匹配后建立关联关系
- 大量分散的使用自定义字符串,例如:ClassUtils,Constants基本沦为摆设
- 模型过于繁杂,各种properties,model,config,store
- 自定义注解应用场景少,DisconfItem与对象一对一关系限制了其使用范围等等限制,而且使用拦截器实现,声明为方法注解增加了代码的实现复杂度,而且这样强制导致用户的实例属性完全受disconf配置控制,即使用户主观的set也不会生效,只会使用disconfCenter中的配置
- 接口定义混乱例如:IReconfigurationAware(这个接口的定义名称是Aware通知,内部定义更像是拦截器)、IDisconfSysUpdate、IDisconfUpdate(DisconfUpdateService备注的同时还要实现该接口,增加了依赖复杂度,接口就足够了,不再需要增加一个注解了)、IDisconfUpdatePipeline、Registry(simple实现根本没有交给工厂管理,而是现场拉出来直接new)、IDisconfDataGetter、DisconfStoreProcessor、DisconfStorePipelineProcessor、ScanStaticStrategy(spring的实现没有使用)
- firstScan,secondScan使用模板方法封装更易读
- 冗余代码过多,File类实现,Item类实现
4.disconf-client重构设计
4.1 优化点
- 消除代码冗余,例如File、Item类实现
- 简化模型,proeprties、model、config、store模块的整合至上下文
- 接口定义抽象更明确其含义的用途,删除无用多余的接口
- 直接废弃自定义注解的实现,如果要实现则改用注册中心的方式进行属性注入,而不是使用切面
- 使用模板方法重构客户端初始化启动
- DisconfMgrBean:start启动
- load:DisconfClientConfigLoadUtil:加载客户端配置至客户端上下文DisconfClientContext:disconfClientConfig
- fetch:FetchUtil:如果开启了远程配置,拉取远程配置中心配置至本地
- configure:将本地properties与配置IPropertyPlaceholderConfigurer绑定替换配置并加载keyBeans缓存key对应的bean实例列表、属性列表
- registerListeners:扫描监听接口IDisconfUpdatePipeline实现,绑定接口监听zk节点NodeWatcher 1. DefaultIDisconfUpdatePipeline:默认监听实现:跟据上下文中的keyBeans获取受影响的bean实例列表,将新value更新至对应的实例
4.2 优化类图设计
- 客户端入口Bean
- 客户端上下文
- load
- fetch
- configure
- registerListeners