插件动态加载的核心是类加载器隔离、接口契约与运行时实例获取的配合,多态仅负责调用时绑定,不参与加载;接口须单独打包为api.jar由宿主统一加载,插件实现类通过自定义ClassLoader加载并由ServiceLoader或配置驱动发现,最终以接口类型接收并交由Spring托管实现生命周期与依赖注入。

多态本身不负责“加载”,它只管“调用时绑定谁”。真正实现插件动态加载的,是类加载器隔离 + 接口契约 + 运行时实例获取这三者的配合。多态的作用,是在加载完成之后,让业务代码完全不用关心具体实现是谁——只要接口一致,就能无缝替换。
接口是多态与插件化的交汇点
框架源码中所有可插拔能力都必须抽象为接口,且该接口需满足:
- 仅声明方法,不含 default 实现、静态字段或框架强依赖(如 Spring 注解)
- 单独打包为 api.jar,由宿主统一加载,确保所有插件看到的是“同一个接口类型”
- 参数用 DTO 或不可变对象,返回值语义明确(如 Result<T>),避免实现类暴露内部细节
加载阶段靠类加载器隔离,不是靠多态
多态无法解决“类从哪来”的问题。框架需通过以下方式完成动态加载:
在 Java 中初始化和管理阿里云 SDK客户端。包括单例模式、线程安全、endpoint 与 region 配置、VPC 终端节点、同步与异步等。
- 每个插件使用独立的 URLClassLoader 或自定义 ClassLoader 实例,打破双亲委派,优先加载自身 jar 中的类
- 接口类必须由宿主类加载器加载;插件实现类由插件加载器加载;实例化后,用宿主加载的接口类型接收,才能安全强转
- 借助 ServiceLoader 扫描 META-INF/services/ 下的实现类名,或通过 YAML 配置驱动加载路径,避免硬编码类名
运行时绑定才体现多态价值
加载完成后,多态机制开始生效:
立即学习“Java免费学习笔记(深入)”;
- 业务代码只持有接口引用,如 NotificationService service,不出现 new XxxNotification() 或 instanceof 判断
- 策略层根据上下文(如请求头、配置项、用户角色)从 Map<String, NotificationService> 中选一个实现,调用其 send() 方法
- JVM 在执行时自动分派到真实子类的方法体,编译期无任何插件类依赖,彻底解耦
容器环境要补足生命周期与注入能力
纯反射加载的对象没有 Spring 管理,会导致 @Autowired 失效、@PostConstruct 不触发。成熟框架的做法是:
- 用 ServiceLoader 获取插件类名 → 再通过 applicationContext.getBean(className, 接口.class) 拿到已托管 Bean
- 插件实现类仍标注 @Service,并由 Spring 扫描注册;ServiceLoader 只做“发现”,Spring 负责“托管”
- 宿主注入 PluginContext,封装配置读取、指标上报、事件发布等能力,避免插件自行调用 ApplicationContext

















