如何设计业务组件动态加载方案
概念
术语 | 意义 |
---|---|
资源包(ResourceArchive, Archive) | Zip包,包含业务组件工程打出来的jar及其依赖的jar,可使用maven-assembly插件打包 |
业务组件 | 需要动态加载并执行的代码,一个资源包中可包含多个业务组件 |
业务组件工程 | 开发业务组件的java工程,允许有依赖 |
我为什么需要动态加载
- 将平台与业务分离,业务只依赖平台api,平台代码层面不依赖业务组件
- 业务组件逻辑相对简单,只有业务逻辑,没有复杂的系统功能,动态加载可降低业务组件的迭代成本
- 能快速响应,快速发布,快速问题悠
- 平台开发人员与业务开发人员分离,得于成百上千的业务组件的开发及维护
为什么不使用OSGI
OSGI确实提供了类隔离能力,但OSGI太重太复杂,难以掌控,我们需要轻量级简单易用的方案
如何设计架构
使用方式
不同角色整个过程如上图,整个体系中包含多个角色,开发者开发业务组件工程,打包成zip后上传到平台,平台会保存上传的zip文件,并做动态加载,当有业务系统请求/消息,平台会调用资源包中的业务组件对请求/消息做处理
能力目标
希望业务组件中只做业务开发,不关心业务开发所需要的资源初始化等问题,平台除了提供动态加载外,还需要为业务组件提供存储,配置,调用外部接口以及预热等能力:
业务组件可使用的能力
对于配置加载,mybatis/hbase等存储的使用以及rest接口的调用,有两种处理方式,一是让业务组件工程自己管理资源的初始化,配置的加载等,但业务组件工程都是轻量级的jar包,业务组件工程的关注点在业务组件的逻辑上,对于业务组件工程来说,处理过多的初始化相关的开发不仅太重,而且有大量的重复建设;第二种方式是平台提供配置初始化和资源初始化的能力,业务组件工程直接使用,这种方式相对要好很多,因此平台有如下非能力型目标:
- 业务组件工程不能太重,不需要处理资源初始化相关的逻辑,需要足够简单
- 遵循约优于配置的原则,避免过多的平台相关的配置
问题抽象
先对前文提到的能力地图做抽象,可对需要的能力分为以下几类:
能力分类
对于这些能力的支持,在加载资源包的时候,需要遵循以下流程:
资源包加载流程
核心概念
经过对问题的抽象,系统主要围绕以下核心概念开展:
- 资源包:依赖的jar以及业务组件工程jar
- 业务组件
- 配置:不同的环境的配置可能不同,比如某个url,可使用maven的profile
- 资源:业务组件工程中使用到的外部资源
- 数据库
- Mybatis
- Hbase
- Etc…
将核心概念抽象成实体并做一定的扩充:
- BizContainer:表示构建业务组件的类,类似于Builder模式,或者以某种方式声明业务组件的类,是业务组件的载体,它是一个隐含的概念,不需要一个类显示的表示
- NamingResource:对资源包中业务组件所使用到的资源的抽象,比如数据源是一个NamingResource,mybatis-mappers也是一个NamingResource,
- ResourceArchive:表示一个资源包,即上传的zip包。在加载资源包时,需要先以一个ResourceArchive为索引初始化配置以及各个NamingResource,再创建业务组件
事件处理
以事件的方式对请求做抽象,事件可分为同步事件和异步事件,一个事件有一个事件标识;
事件通道是在事件的基础上加上了事件类型的概念,事件类型分为http, rpc, mq等,事件类型+事件码唯一表示一个事件通道;
EventDispatcher用于做事件分发,将事件提交给不同的业务组件:
整体架构
通过对领域模型的划分,可得将初始化流程做如下抽象:
架构- 核心流程:加载资源包 -> 识别业务组件 -> 创建业务组件
- 功能性流程通过PostProcessor实现
在此流程模式中,不同的初始化逻辑可通过不同的PostProcessor来实现,不同拦截链的作用如下:
- Archive前置拦截/Archive后置拦截:用于对Archive的初始化做拦截回调处理,比如可在这个拦截链里初始化mybatis、初始化数据源等
- 业务组件前置拦截/业务组件后置拦截:用于对业务组件的创建做拦截回调处理,比如配置的注入、平台服务的注入、创建结果校验代理等