全国免费咨询:

13245491521

VR图标白色 VR图标黑色
X

中高端软件定制开发服务商

与我们取得联系

13245491521     13245491521

2025-03-16_程序员的保命技能——插件扩展点引擎,你必须要了解~

您的位置:首页 >> 新闻 >> 行业资讯

程序员的保命技能——插件扩展点引擎,你必须要了解~ 点击关注公众号,“技术干货”及时达! 业务中台要接入很多的业务方,每个业务方并不是完全相同。很多时候无法完全复用,需要改造系统适应新的业务。 新增业务代码时,务必要保证原有业务不受影响,如果没有插件扩展点能力,就会充斥大量的 if else 。 if (biz == BizA || biz == BizB) { //do some thing //这部分逻辑相同 if (biz == BizA) { //差异化处理 } if(biz == BizB) { //差异化逻辑 }}例如上面的代码,不同的业务线若有差异化逻辑,需要新增分支单独处理。想象一下,当有 10 多个业务接入了你的系统,那么一定让人抓狂…… 任何一个人都无法保证对 10 多种业务完全熟悉,每个人可能只负责 1 个业务,然而如果没有代码逻辑的隔离,维护者只能在千丝万缕中,才能找到目标代码逻辑。更可怕的是,每次新增一个业务,需要在原有的屎山中继续??,不断新增 if else。直到有一天,有一个倒霉蛋改错了代码,导致其他重要业务受影响,引发线上故障。 想象一下,当你改了几行代码以后,要求测试同学,回归10 多个业务线的全部逻辑?这显然不现实。 以上的问题和痛点可归纳为:代码隔离性和业务扩展点问题。解决这两类问题有如下手段! 「使用流程引擎,为不同的业务配置不同的流程执行链」「使用插件扩展引擎,不同的业务实现差异化部分。」MemberClub 中大量使用流程引擎和插件扩展引擎解决业务隔离性和扩展性 问题。 MemberClub是托管在Gitee平台的开源项目,提供了付费会员的交易解决方案,在各类购买场景下提供各类会员形态的履约及售后结算能力,具体介绍可参见 https://gitee.com/juejinwuyang/memberclub 在 程序员的保命技能——流程编排,你一定要了解!文章中,我介绍了流程引擎的设计原理,本篇文章我们分析 扩展点引擎设计。 从以下几个方面了解:扩展点接口的定义、扩展点实现类的定义、加载扩展点地图、引用和调用扩展点 定义扩展点如下接口 PurchaseExtension 抽象了购买域 提交订单和取消订单接口,各产品线提供各自的实现类。实现类要添加 ExtensionProvider 注解,该注解声明了适用的业务线和业务场景。接口实现逻辑中共执行哪些流程。在 submit/cancel接口中 执行流程链。 扩展点接口定义@ExtensionConfig(desc = "购买流程扩展点", type = ExtensionType.PURCHASE, must = true)public interface PurchaseExtension extends BaseExtension { public void submit(PurchaseSubmitContext context);// 提交订单 public void reverse(AfterSaleApplyContext context);//售后逆向 public void cancel(PurchaseCancelContext context);// 取消订单}ExtensionProvider 注解该注解集成了 Service 注解,声明该注解会被加载进 Spring 上下文。同时注解信息包括业务线和业务场景值。 @Target(ElementType.TYPE)@Retention(RetentionPolicy.RUNTIME)@Servicepublic @interface ExtensionProvider { public Route[] bizScenes(); public String desc();}扩展点实现类 加载扩展点ExtensionManage 类在 Spring 启动阶段,从 ApplicationContext 上下文加载 有 ExtensionProvider 注解的修饰的 Bean。注解上声明了 适用的业务线和业务域,并且将以上信息 映射到 Table 中。Table 类是 guava 提供的类似于 HashMap 的工具类,和 Map 不同的是,获取 Table 中的 value 需要 key 和 subKey 两层映射。 在 Table 中,两种映射分别是业务线和 业务场景。 @Getterprivate TableBizTypeEnum, String, ListObject bizExtensionMeta = HashBasedTable.create(); @PostConstructpublic void init() { String[] beanNames = context.getBeanNamesForAnnotation(ExtensionProvider.class); for (String beanName : beanNames) { Object bean = context.getBean(beanName); SetClass interfaces = ClassUtils.getAllInterfacesForClassAsSet(bean.getClass()); ExtensionProvider extension = AnnotationUtils.findAnnotation(bean.getClass(), ExtensionProvider.class); Route[] routes = extension.bizScenes(); for (Class anInterface : interfaces) { if (BaseExtension.class.isAssignableFrom(anInterface)) { for (Route route : routes) { for (SceneEnum scene : route.scenes()) { String key = buildKey(anInterface, route.bizType().getCode(), scene.getValue()); Object value = extensionBeanMap.put(key, bean); if (value != null) { CommonLog.error("注册 Extension key:{}冲突", key); throw new RuntimeException("注册 Extension 冲突"); } CommonLog.info("注册 Extension key:{}, 接口:{}, 实现类:{}", key, anInterface.getSimpleName(), bean.getClass().getSimpleName()); ListObject extensions = bizExtensionMeta.get(route.bizType(), anInterface.getSimpleName()); if (extensions == null) { bizExtensionMeta.put(route.bizType(), anInterface.getSimpleName(), Lists.newArrayList(bean)); } } } } } }} private String buildKey(Class anInterface, int bizType, String scene) { String key = String.format("%s_%s_%s", anInterface.getSimpleName(), bizType, scene); return key;}以上代码地址在:Git 地址 引用扩展点可通过 ExtensionManager.getExtension 方法引用扩展点。如下提单接口代码展示了 如何获取 PurchaseExtension 的实现类。 PurchaseExtension extension = extensionManager.getExtension(context.toDefaultBizScene(),PurchaseExtension.class);extension.submit(context);getExtension 方法中 将通过 产品线和产品域及 接口类,获取到实现类。 public T getExtension(BizScene bizScene, Class tClass) { if (!tClass.isInterface()) { throw new RuntimeException(String.format("%s 需要是一个接口", tClass.getSimpleName())); } if (!BaseExtension.class.isAssignableFrom(tClass)) { throw new RuntimeException(String.format("%s 需要继承 BaseExtension 接口", tClass.getSimpleName())); } String key = buildKey(tClass, bizScene.getBizType(), bizScene.getScene()); T value = (T) extensionBeanMap.get(key); if (value == null) { key = buildKey(tClass, BizTypeEnum.DEFAULT.getCode(), SceneEnum.DEFAULT_SCENE.getValue()); value = (T) extensionBeanMap.get(key); } if (value == null) { throw new RuntimeException(String.format("%s 没有找到实现类%s", tClass.getSimpleName(), bizScene.getKey())); } return value;}最后MemberClub 中大量使用流程引擎和插件扩展引擎解决业务隔离性和扩展性 问题,以上代码均可以在 MemberClub项目中找到。代码地址:Git地址 点击关注公众号,“技术干货”及时达! 阅读原文

上一篇:2020-11-24_「转」创业者施一公 下一篇:2023-04-05_「转」住八平米的房子,好爽!

TAG标签:

18
网站开发网络凭借多年的网站建设经验,坚持以“帮助中小企业实现网络营销化”为宗旨,累计为4000多家客户提供品质建站服务,得到了客户的一致好评。如果您有网站建设网站改版域名注册主机空间手机网站建设网站备案等方面的需求...
请立即点击咨询我们或拨打咨询热线:13245491521 13245491521 ,我们会详细为你一一解答你心中的疑难。
项目经理在线

相关阅读 更多>>

猜您喜欢更多>>

我们已经准备好了,你呢?
2022我们与您携手共赢,为您的企业营销保驾护航!

不达标就退款

高性价比建站

免费网站代备案

1对1原创设计服务

7×24小时售后支持

 

全国免费咨询:

13245491521

业务咨询:13245491521 / 13245491521

节假值班:13245491521()

联系地址:

Copyright © 2019-2025      ICP备案:沪ICP备19027192号-6 法律顾问:律师XXX支持

在线
客服

技术在线服务时间:9:00-20:00

在网站开发,您对接的直接是技术员,而非客服传话!

电话
咨询

13245491521
7*24小时客服热线

13245491521
项目经理手机

微信
咨询

加微信获取报价