
在 Spring 应用中集成 OptaPlanner 时,可通过 SolverManager 的回调机制(如 finalBestSolutionListener)或 SolverJob.getFinalBestSolution() 同步/异步监听求解结束并安全获取最优解,无需轮询或阻塞主线程。
在 spring 应用中集成 optaplanner 时,可通过 `solvermanager` 的回调机制(如 `finalbestsolutionlistener`)或 `solverjob.getfinalbestsolution()` 同步/异步监听求解结束并安全获取最优解,无需轮询或阻塞主线程。
OptaPlanner 本身不提供传统“运行完成”事件钩子,但其现代异步求解器设计(尤其配合 SolverManager)天然支持生命周期感知——这是 Spring 环境下实现优雅结果处理的关键。
✅ 推荐方案:使用 SolverManager.solve() + 回调监听
SolverManager 是 OptaPlanner 官方推荐的线程安全、可扩展的求解入口,支持基于 CompletableFuture 的异步执行与回调:
// 假设已注入 @Autowired private SolverManager<MySolution, Long> solverManager;
Long problemId = System.currentTimeMillis();
solverManager.solve(
problemId,
() -> myProblemFactory.createProblem(), // Supplier<Solution>
finalBestSolution -> {
// ✅ 此处 guaranteed 被调用一次,且仅当求解终止(超时/最优/异常中断)
log.info("Solver finished. Best score: {}", finalBestSolution.getScore());
saveResultToDatabase(finalBestSolution);
notifyClientViaWebSocket(finalBestSolution);
}
);该方式简洁可靠,适用于大多数场景:求解完成后自动触发业务逻辑(如持久化、通知、UI 更新),且完全非阻塞。
✅ 进阶方案:solveAndListen() 实现中间解+终解双监听
若需实时反馈优化进度(例如前端显示迭代过程),应使用 solveAndListen:
solverManager.solveAndListen(
problemId,
() -> myProblemFactory.createProblem(),
bestSolution -> {
// ? 每次找到新最佳解时调用(含初始解)
updateProgressDashboard(bestSolution);
},
finalBestSolution -> {
// ✅ 仅在求解彻底结束时调用(无论因超时、最优或中断)
log.info("Optimization completed. Final score: {}", finalBestSolution.getScore());
sendCompletionEvent(finalBestSolution);
},
throwable -> {
// ⚠️ 可选:自定义异常处理器(默认会记录 ERROR 日志)
log.error("Solver failed for problem {}", problemId, throwable);
handleSolverError(problemId, throwable);
}
);? 注意:solveAndListen() 内部会持续监听 SolverJob 状态变化,因此需确保 throwable 处理器不抛出未捕获异常,否则可能影响后续任务调度。
✅ 同步等待方案(慎用):getFinalBestSolution()
虽不推荐在 Web 请求线程中直接阻塞,但在批处理、测试或简单 CLI 场景下可同步获取结果:
SolverJob<MySolution, Long> job = solverManager.solve(problemId, () -> createProblem()); MySolution solution = job.getFinalBestSolution(); // 阻塞直到完成(或超时) // ✅ 此时 solution 已确定为最终最优解(或最后可行解)
⚠️ 重要限制:getFinalBestSolution() 默认最多等待 solverManager 配置的 jobTimeout(默认 5 分钟),超时将抛出 ExecutionException;建议始终配合 try-catch 并设置合理超时策略。
? 最佳实践总结
- 永远优先使用 SolverManager,而非直接创建 Solver 实例(后者无法被 Spring 管理生命周期,易引发内存泄漏);
- 避免轮询 Solver.isSolving() 或 Solver.getBestSolution() —— 这不仅低效,还可能读取到未完成的中间状态;
- 监听器中禁止执行耗时操作(如远程 HTTP 调用、大文件写入),建议委托至 @Async 方法或消息队列;
- 在 Spring Boot 中,通过 @ConfigurationProperties 统一配置 SolverManager 的线程池、超时及重试策略,提升系统稳定性。
通过上述任一方式,您即可精准捕获 OptaPlanner 求解结束信号,并安全、可靠地消费最终优化结果。

















