
在 Spring 应用中集成 OptaPlanner 时,可通过 SolverManager 的回调机制(如 finalBestSolutionListener)或 SolverJob.getFinalBestSolution() 同步/异步监听求解结束,精准捕获最终解并触发后续业务逻辑。
在 spring 应用中集成 optaplanner 时,可通过 `solvermanager` 的回调机制(如 `finalbestsolutionlistener`)或 `solverjob.getfinalbestsolution()` 同步/异步监听求解结束,精准捕获最终解并触发后续业务逻辑。
OptaPlanner 本身不提供传统“运行完成”事件钩子,但其现代异步求解核心 SolverManager 提供了完善的生命周期通知能力。关键在于避免直接使用阻塞式 Solver.solve()(已不推荐),转而采用 SolverManager 管理求解任务——它天然支持回调、超时、并发控制及结果监听。
✅ 推荐方案一:使用 solve() + 最终解回调(简洁可靠)
适用于单次求解且需在结果就绪后立即处理的场景:
@Service
public class PlanningService {
private final SolverManager<mysolution long> solverManager;
public PlanningService(SolverManager<mysolution long> solverManager) {
this.solverManager = solverManager;
}
public void startSolving() {
solverManager.solve(
1L, // problemId(唯一标识,用于后续查询或取消)
() -> createInitialSolution(), // problem supplier
finalBestSolution -> {
// ✅ 此处 guaranteed 执行:求解终止(无论最优/超时/异常中断)
System.out.println("Solver finished. Best score: " + finalBestSolution.getScore());
saveResult(finalBestSolution);
notifyClient(finalBestSolution);
}
);
}
}</mysolution></mysolution>
⚠️ 注意:该回调在求解线程池中执行,若涉及 I/O 或耗时操作(如数据库写入、HTTP 调用),建议显式切换至 @Async 或自定义线程池,避免阻塞 OptaPlanner 内部线程。
✅ 推荐方案二:使用 solveAndListen() 实现中间解+最终解双监听
适用于需实时展示优化进度(如 Web UI 进度条、日志流)的交互式应用:
public void startInteractiveSolving() {
solverManager.solveAndListen(
1L,
() -> createInitialSolution(),
// 中间解监听(每找到更优解即触发)
intermediateSolution -> {
log.info("New best solution found: {}", intermediateSolution.getScore());
updateProgressUI(intermediateSolution);
},
// 最终解监听(求解终止时触发,与 solve() 的回调语义一致)
finalBestSolution -> {
log.info("Optimization completed. Final score: {}", finalBestSolution.getScore());
publishResultToKafka(finalBestSolution);
},
// 异常处理器(可选,不传则使用默认处理器)
(problemId, throwable) -> {
log.error("Solver failed for problem {}", problemId, throwable);
handleSolveFailure(problemId, throwable);
}
);
}
✅ 方案三:同步等待结果(仅限测试或简单脚本)
通过 SolverJob.getFinalBestSolution() 主动阻塞获取结果(内部调用 CompletableFuture.get()):
public MySolution solveAndWait(long timeoutSeconds) throws InterruptedException, ExecutionException {
SolverJob<mysolution long> job = solverManager.solve(
System.currentTimeMillis(),
() -> createInitialSolution()
);
// 阻塞等待,最多 timeoutSeconds 秒;超时抛出 TimeoutException
return job.getFinalBestSolution(timeoutSeconds, TimeUnit.SECONDS);
}</mysolution>
? 补充说明:getFinalBestSolution() 返回 null 仅当求解被主动取消(job.cancel());若超时终止,仍返回截止时的最佳解(非 null)。务必配合 try-catch 处理 ExecutionException(含底层 OptaPlanner 异常)和 TimeoutException。
? 关键注意事项
- Spring 集成前提:确保已正确配置 SolverManager Bean(通常通过 @Bean 注入 SolverFactory 并调用 SolverManager.create());
- 线程安全:SolverManager 是线程安全的,可全局单例复用;
- 资源清理:SolverManager 内部维护线程池,应用关闭时应调用 solverManager.destroy()(Spring Boot 自动管理);
-
异常传播:未显式提供异常处理器时,solveAndListen() 的异常会由 ForkJoinPool.commonPool() 捕获并静默吞没——强烈建议始终传入 BiConsumer
处理器。
通过以上任一方式,您即可彻底告别“盲等求解结束”的困境,在 Solver 停止瞬间精准响应,实现结果落地、状态更新与系统联动。










