Java模块系统中的provides … with …是JPMS中声明服务实现的专用语法,用于在module-info.java中指明某模块提供某接口的具体实现类,需配合requires依赖声明和ServiceLoader运行时加载。
“provides with”不是标准编程术语,也不是主流语言(如java、c#、c++、python)中内置的语法结构。它不对应任何官方关键字、设计模式名称或框架原语。实际开发中若听到类似表述,大概率是混淆了概念——比如把模块系统中的 provides(如java 9+模块声明里的 provides … with …)误当作通用设计模式,或把依赖注入中的“提供某服务实例”口语化表达为“provides with”。
Java模块系统中的 provides … with … 是什么
这是 Java Platform Module System(JPMS)中用于声明**服务实现**的专用语法,仅出现在 module-info.java 文件里,作用是告诉运行时:“本模块提供某种服务接口,并由某个具体类来实现它”。
示例:
module my.plugin.impl {
requires my.plugin.api;
provides my.plugin.api.TextProcessor with my.plugin.impl.UTF8Processor;
}
含义:该模块实现了 TextProcessor 接口,具体实现类是 UTF8Processor。主程序可通过 ServiceLoader.load(TextProcessor.class) 在运行时自动发现并加载它。
关键点:
- 必须配合
requires声明对服务接口模块的依赖 - 实现类必须有无参构造器且是 public 的
- 运行时靠
ServiceLoader查找META-INF/services/接口全限定名文件(但使用provides … with …后可省略该文件) - 它本身不负责“动态加载DLL”或“热插拔”,只是模块层面的服务注册契约
真正支撑动态扩展变量功能模块的核心机制
所谓“变量功能模块”,通常指可配置、可替换的行为单元(如不同规则引擎、不同数据校验策略、不同字段计算逻辑)。要实现其动态扩展,需组合以下技术:
✅ 定义统一契约:用接口或抽象类封装变量行为,例如
public interface VariableEvaluator {
String getName();
Object evaluate(Map<String, Object> context);
}
✅ 运行时发现与加载:
- Java:用
ServiceLoader(配合provides … with …或传统META-INF文件) - .NET:用
Assembly.LoadFrom()+GetTypes().Where(t => t.IsClass && typeof(IPlugin).IsAssignableFrom(t)) - C++:用
dlopen()/LoadLibrary()获取句柄,再通过符号查找(如dlsym)获取工厂函数地址
✅ 变量功能的上下文注入:主程序不硬编码参数,而是传入运行时环境(如用户输入、配置Map、当前会话ID),让插件自行决定如何读取和处理变量。
一个轻量级实战:Java中动态加载变量计算插件
假设系统需要支持多种“订单金额计算方式”(基础价、含税价、会员折后价),且允许运维随时放入新JAR包启用新算法。
步骤简述:
- 创建接口模块
variable-api,定义OrderAmountCalculator接口 - 创建插件模块
calculator-tax,实现接口,并在module-info.java中写:
provides OrderAmountCalculator with TaxInclusiveCalculator; - 主程序启动时扫描
plugins/目录,用ModuleLayer.defineModulesWithOneLoader()加载新模块层 - 调用
ServiceLoader.load(layer, OrderAmountCalculator.class)获取全部可用实现 - 根据配置项(如
calc.strategy=tax)选择对应插件执行evaluate(context)
这样,新增一种计算方式只需写一个类、编译成模块JAR、丢进插件目录、改个配置——无需重启主程序,也不修改核心代码。
为什么不能只靠 “provides with” 完成整个插件化
它只是模块系统中的一环,解决的是“谁实现了什么服务”的声明问题。完整插件化还需:
- 可靠的插件发现路径(文件系统监听 or 数据库注册 or 配置中心下发)
- 类加载隔离(避免插件间、插件与主程序的类冲突)
- 生命周期管理(初始化、启用、停用、卸载)
- 错误隔离与降级(某个插件崩溃不影响全局)
- 版本兼容策略(如接口升级时旧插件仍可运行)
这些都超出了 provides … with … 的职责范围。

















