
当需在单个应用中使用多个规划问题解决方案时,必须为每个 @PlanningSolution 类单独创建 SolverConfig 实例,并确保每个解决方案类均标注 @PlanningSolution;直接在 XML 或全局配置中指定未注解的类将触发非法状态异常。
当需在单个应用中使用多个规划问题解决方案时,必须为每个 `@planningsolution` 类单独创建 `solverconfig` 实例,并确保每个解决方案类均标注 `@planningsolution`;直接在 xml 或全局配置中指定未注解的类将触发非法状态异常。
在 Timefold(OptaPlanner 的现代演进分支)中,支持在同一应用内管理多个独立的规划场景——例如,一个用于员工排班(ShiftSchedule),另一个用于车辆路径规划(VehicleRoutePlan)。但关键前提在于:每个解决方案类都必须显式声明 @PlanningSolution 注解,且不能依赖统一的 XML 配置文件“复用”未注解的类。
✅ 正确做法:为每个方案独立构建 SolverConfig
// 方案1:员工排班
SolverConfig config1 = new SolverConfig()
.withSolutionClass(ShiftSchedule.class) // 必须已标注 @PlanningSolution
.withEntityClasses(Employee.class, Shift.class)
.withConstraintProviderClass(ShiftSchedulingConstraintProvider.class)
.withTerminationConfig(new TerminationConfig().withSecondsSpentLimit(30L));
// 方案2:物流路径优化
SolverConfig config2 = new SolverConfig()
.withSolutionClass(VehicleRoutePlan.class) // 同样必须标注 @PlanningSolution
.withEntityClasses(Vehicle.class, Visit.class)
.withConstraintProviderClass(VrpConstraintProvider.class)
.withTerminationConfig(new TerminationConfig().withBestScoreLimit("0hard/0soft"));
// 分别创建 SolverManager 实例(推荐方式)
SolverManager<ShiftSchedule, Long> shiftSolverManager
= SolverManager.create(config1);
SolverManager<VehicleRoutePlan, Long> vrpSolverManager
= SolverManager.create(config2);⚠️ 注意事项:
- 所有
solutionClass(如ShiftSchedule、VehicleRoutePlan)必须包含@PlanningSolution注解,否则SolverFactory.create()将抛出IllegalStateException;- 不可复用同一
SolverConfig实例指向多个解决方案类;- Quarkus/Spring Boot 自动装配目前不支持多
@PlanningSolution场景(会尝试扫描并注册所有带注解类,但无法区分约束提供者与求解器绑定关系),因此应绕过自动配置,采用编程式SolverManager.create(config);- 若需运行时动态切换方案,建议封装
SolverManager实例池,并通过业务标识(如solverType: "shift" | "vrp")路由请求。
? 总结
Timefold 原生支持多解决方案架构,但要求严格遵循契约:每个 solutionClass 是且仅是 @PlanningSolution 标注的 POJO,且每个 SolverManager 绑定唯一 SolverConfig。放弃 XML 全局配置、改用代码化配置是实现灵活多场景规划的关键一步。如需框架级简化(如 @Named("shift-solver") 支持),可向 Timefold GitHub 提交功能提案。

















