改需求 ≠ 改主干
二开包以 owner: custom 在构建期打进宿主,零运行时开销;官方发版覆盖不到你的实现,升级不再人人自危。
HouMall 是面向真实交易场景的插件化开源商城系统: BFF 作为唯一入口兼任网关,PF4J 插件运行时负责安装、启停与扩展点分发, 官方主干、二次开发、第三方插件三条通道共用同一套契约却互不干扰。 改价格算法不必改主干,装 ERP 不必重启商城。
code: mall-coupon
name: 优惠券
version: 1.2.0
owner: thirdparty # official | custom | thirdparty
runtime: embedded # embedded | standalone
host: mall
extensions:
- point: goods.PriceCalcExtension
class: com.houjiang.coupon.ext.CouponPriceCalc
priority: 100
menus:
- { path: /mall/coupon, title: 优惠券, sort: 3610 }
frontend:
entry: /plugin-assets/mall-coupon/1.2.0/index.mjs
一份 plugin.yaml 同时驱动:扩展点注册、菜单注入、接口路由、前端资源加载。
是客户要改一句价格算法,你就得 fork 一份主干;是卖出去的 ERP 和商城死死耦合;是每接一个新渠道都要重新发版。
二开包以 owner: custom 在构建期打进宿主,零运行时开销;官方发版覆盖不到你的实现,升级不再人人自危。
ERP、OA、财务、MES、收银台、配送以独立插件制品交付。装了才有菜单、接口和表;没装,Core 照常登录、浏览、下单、支付。
高频链路(认证、定价、下单、库存、支付)在启动期冻结成不可变快照;单个扩展点 200ms 超时、异常只记录不传播。
下列能力均有对应源码模块与文档落点,不是 Roadmap 上的空头支票。
商品 SPU/SKU/分类/品牌/库存、订单与售后、支付(微信 / 支付宝 / 余额)与对账、商户入驻与结算、供应商协同,覆盖完整交易闭环。
bff-web 是浏览器请求的唯一 HTTP 入口,承担鉴权、租户上下文、DTO 聚合与插件代理,不额外部署一层网关;限流 / WAF / TLS 交给 Nginx 与云 LB。
/web/** 统一路由/web/plugin/{code}/** 泛化分发插件的概览、筛选、安装、启停、卸载与配置抽屉,配合市场商品、版本、License 授权;制品落盘后做摘要与签名校验。
hou_addon_plugin 安装态PluginArtifactStore 校验扩展点契约统一收在 plugin-api,实现随插件或二开。当前内置 11 个:定价、库存变更、运费、下单前后、支付回调、登录后、菜单注入、仪表盘、促销三件套。
宿主通过远程 ESM import() 加载插件产物,动态 router.addRoute、自动注入菜单、卸载触发 teardown,加载失败自动兜底。
ctx.callApi平台管理后台、商城 PC 前台、uni-app 移动端、商家端、供应商端、会员中心、IM 客服、内容管理、收银台与配送端,共 17+ 前端应用。
所有设计只回答一个问题:新能力进来时,谁都不用动。
/web/plugin/**backend/contracts/{module}-api,按需建立的稳定契约frontend/admin 等前端
→ BFF(入口 + 鉴权 + 租户上下文 + 聚合 + 插件代理)
→ Core PaaS 平台服务
→ 商城核心领域(goods / order / payment / merchant / supplier / mall)
→ 扩展点快照(官方 · 二开 · 插件 · 降级)
→ 数据库 / 消息 / 对象存储 / 第三方平台
plugin-api全部模块在 backend/paas/ 平级组织,多进程 + Nacos + OpenFeign,不堆层级。
| 模块 | 职责 | 归属 |
|---|---|---|
commons | 公共基础(DTO / VO / 工具 / Token) | Core |
auth | 认证授权 | Core |
base | 基础数据(地区 / 配置 / 文件 / 短信 / 邮件) | Core |
permission | 角色、菜单、数据权限 | Core |
userms | 用户、员工、组织 | Core |
thirdparty | 短信 / 邮件 / OSS / 企微 / 钉钉 / 飞书等通用外部能力 | Core |
goods | 商品 SPU / SKU / 分类 / 品牌 / 库存 | Core |
order | 下单、退款、物流、售后 | Core |
payment | 支付渠道、余额、对账 | Core |
merchant | 商家入驻、店铺、结算 | Core |
supplier | 供应商协同 | Core |
mall | 插件中心宿主 + 插件引擎装配 + 商城聚合宿主 | Core |
plugin-sdk / plugin-engine | 插件开发 SDK 与 PF4J 运行时 | Core |
erp · oa · finance · mes | 企业资源计划 / 协同办公 / 财务 / 生产执行 | 商业插件 |
webpos · rider · dcenter | 门店收银台 / 骑手 / 配送调度 | 商业插件 |
一份 plugin.yaml 加 owner / runtime 两个开关,派生出内建服务、内建能力、二开包、第三方插件四种形态。学一次,会两种交付。
| 通道 | 身份 | 生效时机 | 典型场景 |
|---|---|---|---|
| A 官方主干 | owner: official | 发版重启 | 商品、订单、优惠券 |
| B 二开覆盖 | owner: custom | 构建期打进宿主 | 改价格算法、换 OSS |
| C 插件热插拔 | owner: thirdparty | 运行期热插拔 | 拼团、新推送通道 |
关键区别:二开是「换掉」官方实现(构建期、零运行时开销);插件是「追加」官方钩子(运行期、有注册开销)。
// backend/extensions/custom-goods —— 不改一行主干,覆盖定价
@HouExtension(
point = "goods.PriceCalcExtension",
owner = "custom", // 官方 priority = 0,二开 = 100
priority = 100
)
public class VipPriceCalc implements PriceCalcExtension {
@Override
public void execute(PriceCalcContext ctx) {
long amount = ctx.in().getSkuAmount();
if (ctx.in().getUserLevel() >= 3) {
ctx.out().setPayAmount(amount * 9 / 10); // 会员 9 折
}
}
}
code: custom-goods
name: 商品二开包
version: 1.0.0
owner: custom
runtime: embedded
host: mall
apis:
- plugin-api
- goods-api
// 插件前端:ESM 产物由宿主远程加载,自动注册路由与菜单
export default {
install(ctx) {
ctx.addRoute({ path: '/mall/coupon', component: () => import('./views/Coupon.vue') });
ctx.callApi('/coupon/list'); // 收敛到 /web/plugin/mall-coupon/**
},
teardown() { /* 卸载时清理 */ }
}
下面每条命令都来自项目实际构建链路,不是示意。
git clone <你的仓库地址> houcloud && cd houcloudplugin-platform 是反应堆根,先把 plugin-sdk 与 plugin-api 装进本地仓库。
cd plugin-platformmvn -o -q -DskipTests -pl sdk/plugin-sdk,../backend/contracts/plugin-api install按需构建,-am 会自动带上依赖模块;对外入口 bff-web 默认端口 8391。
mvn -DskipTests -pl bff/bff-web -am clean packagecd frontend/admin && npm install && npm run devNoClassDefFoundError,后端构建请务必带 clean。
阶段之间必须通过上一阶段的验收门禁:工作完成、产物存在、验证通过、文档同步,四条同时满足才算 OK。
模块归属、目录决策、商业插件边界与二开形态定稿
契约抽取、扩展点契约、二开依赖白名单与契约测试门禁
/web/plugin/{code}/** 通道、插件中心 / 市场 / License 服务
PF4J 装载、扩展点注册与不可变快照、集成测试闭环
插件中心页面、动态路由、菜单注入与前端资源加载
首个完整商业插件纵向迁移,验证独立交付与授权
多商业插件共存与跨域协作走 Core 事件与扩展点
分销、积分、返利、风控、装修等聚合业务插件化
性能、trace/metrics、灰度回滚与运维 tooling 完善
Core(认证、权限、用户组织、商品、订单、支付、商户、供应商、第三方基础能力、插件中心与插件引擎)全部开源。ERP、OA、财务、MES、收银台、骑手配送以及商城营销类聚合能力以独立插件制品交付,未安装时 Core 依然可以独立登录、浏览、下单和完成基础支付。
区别在于「换掉」还是「追加」:二开(owner: custom)在构建期打进宿主,用来替换官方实现,零运行时开销;插件(owner: thirdparty)在运行期热插拔,用来追加官方钩子。两者的元数据、目录结构、前端契约与扩展点写法完全一致。
扩展点在注册与卸载期生成按优先级冻结的不可变快照,读路径零复制零排序;单个扩展点 200ms 超时,插件异常只记录不向上传播;没有插件时链路零开销。高频链路(认证、定价、下单、库存、支付)都走快照,不扫描 Class、不扫描插件目录。
BFF 已经在做统一入口、鉴权、租户上下文与前端聚合,再加一层独立业务网关只会多一跳和一套配置。限流、WAF、TLS、负载均衡交给 Nginx 与云 LB 更合适,这是架构决策 D1 的结论。
可以。项目以 MIT 协议开源,允许商用、修改、分发与再许可,只需保留版权声明。注意商业插件制品与授权不包含在 Core 的开源范围内。