关键在于继承管“身份与生命周期”、多态管“行为替换”:抽象基类定义元信息、强制扩展点与状态机,接口组合注入Validator/Notifier/StorageAdapter等可变行为,SPI+工厂实现运行时多态绑定,事件总线解耦通信。

关键在于让继承管“身份与生命周期”,让多态管“行为替换”,两者不混用、不越界。插件系统不是靠一层层 extends 堆出来,而是靠抽象基类定骨架、接口定义能力、运行时靠多态绑定具体实现。
继承只做三件事:定义元信息、声明扩展点、管理状态
顶层抽象类(如 Plugin)不写业务逻辑,只做架构级约束:
- 封装固定字段:id、version、enabled(protected,子类可读不可乱改)
- 强制声明抽象方法:init()、execute(Context)、destroy()——这是每个插件必须回答的“存在性问题”
- 提供受控模板方法:safeExecute() 内部按序调用 before() → execute() → after(),其中 before()/after() 是空的 protected 方法,子类按需覆写,不覆写也不影响主流程
- 内置状态机(如 enum PluginState { INITIALIZING, READY, RUNNING, STOPPED }),state 变量由父类统一维护,子类不能直接赋值
多态靠接口组合,不靠继承叠加行为
具体功能不塞进继承链,而是通过接口委托注入:
在 Java 中初始化和管理阿里云 SDK客户端。包括单例模式、线程安全、endpoint 与 region 配置、VPC 终端节点、同步与异步等。
- 校验逻辑走 Validator 接口,可传入 DefaultValidator 或 OrderAmountValidator,运行时替换不影响插件主体
- 通知能力走 Notifier 接口,邮件、短信、Webhook 各自实现,插件只调 notify(result),不关心怎么发
- 存储适配走 StorageAdapter 接口,MySQL/Redis/文件系统自由切换,插件只调 save(data)
- 所有组合对象声明为 final 字段,构造器注入,杜绝运行中被篡改;调用一律走 this.validator.validate(ctx),不暴露内部细节
加载与通信必须脱离编译期依赖
插件不是 new 出来的,也不能靠 instanceof 判断类型:
立即学习“Java免费学习笔记(深入)”;
- 用 Java SPI(META-INF/services/com.example.Plugin)自动发现实现类,或配置驱动(YAML 中写 plugins: ["payment-alipay", "log-file"])
- 插件工厂返回的是 Plugin 接口类型,宿主代码只写 plugin.execute(ctx),JVM 运行时自动分派到真实子类
- 插件之间不通类引用,通信走事件总线(EventBus.post(new PaymentSuccessEvent()))或上下文透传(Context.put("traceId", id))
- 每个插件持有一个 PluginContext,里面封装 ConfigReader、MetricsReporter 等细粒度接口,不暴露 SpringContext 或全局单例
预留钩子比硬编码判断更可持续
不要在父类里写 if (type == "wechat"),而是在关键节点留空方法供子类介入:
- beforeExecute()、onError(Throwable)、afterPersist() 这类 protected 钩子方法,默认空实现
- 子类只覆写需要的部分,不覆写也不报错,避免强制实现带来的负担
- Javadoc 明确标注调用时机,比如 “在 execute() 执行前、事务开启后触发”
- 未来新增钩子只需加方法,不破坏已有子类,比改抽象方法签名安全得多

















