轻量化平台化框架——shuke
在对一个履约系统进行平台化改造过程中,沉淀了一套轻量化的平台化框架——shuke,供大家参考。
1. 背景
要重构的这一履约系统作为一个历史悠久的应用,各层代码中堆砌着各种针对不同业务的if else逻辑,进而导致了几个问题:
- 代码可读性很差。
- 业务代码和平台代码高度耦合。
- 新业务接入困难。
举一个例子,
履约平台在商家呼叫运力时,需要把履约任务下发给CP,而不同的业务下发的CP也是不一样的。
重构之前代码是这样的:
业务代码和平台代码混杂在一起,且层层if else嵌套
- 对业务的修改可能引起平台逻辑的问题
- 对A业务的修改可能引发B业务的问题
- 可读性很差,很难在一个业务包中找到所有的业务个性化定制
- 新业务接入成本高,需要找到各种需要修改的点,加if else
在系统重构的过程,通过shuke这一平台化框架,最终达到以下几个目标:
- 解耦业务逻辑和平台逻辑
- 提升代码可维护性
- 降低新业务的接入成本
2. 使用说明
talk is cheap, show me the code.
重构完之后,效果是这样的
- 平台层定义spi
public interface DispatchNode {
DispatchNO dispatch2Cp(DispatchNOParam param);
}
- 平台使用spi
DispatchNode dispatchNode = PluginRouter.routeNode(DispatchNode, FlowId.CHINA);
DispatchNO dispatchNO = dispatchNode.dispatch2Cp(param);
System.out.println(dispatchNO);
- 业务A实现spi
@Component
@FlowInfo(FlowId.USA) // 业务身份
public class UsaDispatchNode implements DispatchNode {
@Resource
private CainiaoService cainiaoService;
@Override
DispatchNO dispatch2Cp(DispatchNOParam param);
String expressNumber = cainiaoService.dispatch(xxx);
return DispatchNO.builder()
.result(expressNumber)
.build();
}
}
- 业务B实现spi
@Component
@FlowInfo(FlowId.CHINA) // 业务身份
public class ChinaDispatchNode implements DispatchNode {
@Resource
private FnService fnService;
@Override
DispatchNO dispatch2Cp(DispatchNOParam param);
String expressNumber = fnService.dispatch(xxx);
return DispatchNO.builder()
.result(expressNumber)
.build();
}
}
通过以上代码,便可以把业务代码和平台代码解耦开来。以后无论是现有业务的维护还是新业务的接入,都可以快速高效进行。
3. 组成
shuke涉及的部分有以下以下几部分:
- spi
- 也就是平台留给业务的拓展点
- 业务spi实现
- 不同的业务对spi有其不同的实现
- 平台
- 通用的平台代码,通过spi来隔离不同业务的定制点
- ability
- 平台能力,提供给插件方来使用。
最终的各模块之前的关系如下:
4. 设计哲学 && 其他框架对比
KISS:Keep it simple, keep it stupid.
Shuke设计的一大初衷便是足够的简单和轻量化,这也是shuke区分于现有的一些重量级平台化框架的最重要的特点。
相比于那些花费漫长时间学习上手、理解的平台化框架,shuke的一大特点是可以在几十分钟内了解其如何使用。学习成本的降低,意味着开发成本和犯错的机会都会随之降低。
5. todo
做一个一个新生的框架,目前在一些地方还是待完善的,比方说不同业务方只有代码隔离没有容器隔离、业务插件不支持热部署等等,这些都是后续可以改进的地方。
6. 源码
git@gitlab.alibaba-inc.com:zhongzheng.czz/shuke.git
测试用例:
com.alibaba.ascp.shuke.core.test.ShukeTest#testDispatch
有什么意见或者建议,欢迎留言~