从 OptaPlanner 7.x 到 8.x,我们只改了 3 个地方

发布时间:2026/9/12 16:39:01

从 OptaPlanner 7.x 到 8.x,我们只改了 3 个地方 一次“受控恐慌”后的冷静迁移一、起因一次并不严重的“事故”事情是从测试环境的一句日志开始的。那天上午测试同学反馈APS 排产偶尔点完按钮页面一直转圈。​后台日志里没有明显的Exception但有一个线程长时间处于WAITING状态。重启服务后问题消失。再跑几次又复现但概率很低。我们第一反应是“是不是 JDK 17 OptaPlanner 7.x Drools 的老问题终于爆了”老实说当时心里是有点慌的。毕竟 APS 是生产核心模块谁也不想背一个“排产算不出来”的锅。二、决策不是“大升级”而是“小修补”在翻了一圈 OptaPlanner 的 issue 和社区讨论后我们发现这个问题在 8.x 里被反复提及但没有明确的“已修复”标记7.x 官方早已停止维护但 8.x 的 API 变动看起来“可控”于是我们定了一个原则不动业务逻辑只动“不得不改”的地方。换句话说这不是一次“架构升级”而是一次“打补丁式的迁移”。三、真正改动的只有这 3 个地方事后统计我们一共改了3 个文件加起来不到 50 行代码。1️⃣ApsConstraintProviderpenalize() 变得“更数学了”这是我们最早碰到的编译错误。7.x 的老代码private Constraint capabilityConflict(ConstraintFactory constraintFactory) { return constraintFactory.from(Task.class) .filter(t - { if (t.getResourceBo() null) { return false; } if (CollUtil.isEmpty(t.getResourceBo().getCapabilityIds())) { return true; } else { return !t.getResourceBo().getCapabilityIds() .containsAll(t.getCapabilityIds()); } }) .penalize(Capability conflict, HardSoftScore.ofHard(10)); }8.x 的新写法private Constraint capabilityConflict(ConstraintFactory constraintFactory) { return constraintFactory.from(Task.class) .filter(t - { if (t.getResourceBo() null) { return false; } if (CollUtil.isEmpty(t.getResourceBo().getCapabilityIds())) { return true; } else { return !t.getResourceBo().getCapabilityIds() .containsAll(t.getCapabilityIds()); } }) .penalize(HardSoftScore.ONE_HARD) .multiply(10); }我们在 Code Review 时是怎么解释的我当时跟同事说“以前是‘一次性扣 10 分’现在是‘先扣 1 分再放大 10 倍’。”听起来像文字游戏但其实语义更清晰了ONE_HARD是一个单位惩罚.multiply(10)是权重系数以后如果要把权重放到配置中心这个写法会非常自然.multiply(penaltyConfig.getCapabilityConflictWeight())这不是语法糖这是可维护性的提升。2️⃣StartTimeUpdatingVariableListener从“地下”走到“地上”这个改动是最让我舒服的一个。7.x 的 importimport org.optaplanner.core.impl.domain.variable.listener.VariableListener; import org.optaplanner.core.impl.score.director.ScoreDirector;8.x 的 importimport org.optaplanner.core.api.domain.variable.VariableListener; import org.optaplanner.core.api.score.director.ScoreDirector;为什么这是个好信号因为impl这个包名在 Java 世界里通常意味着一句话“别碰我我随时可能变。”我们之前写VariableListener心里多少有点“偷用内部 API”的不安。现在它被挪到api包说明了一件事OptaPlanner 承认你写的这种监听器是合法扩展。这对我们这种“自己维护影子变量”的 APS 系统来说是个定心丸。3️⃣ScoreDirector字符串 → Lambda最实用这可能是日常开发中感知最强的一个变化。7.x 的写法scoreDirector.beforeVariableChanged(task, planStartTime); task.setPlanStartTime(newTime); scoreDirector.afterVariableChanged(task, planStartTime);8.x 的写法scoreDirector.beforeVariableChanged(task, Task::getPlanStartTime); task.setPlanStartTime(newTime); scoreDirector.afterVariableChanged(task, Task::getPlanStartTime);我们为什么喜欢这个改动举个真实的例子有一次我们重构Task类把字段从planStartTime改成了startTime。在 7.x 时代这类改动非常危险Java 编译器不知道你在字符串里写的是什么只有运行时才会抛异常单元测试稍不注意就漏掉但在 8.xIDE 直接标红重构字段名lambda 自动跟着改编译期就把问题拦住了我当时在群里发了一句“就冲这个 lambda这趟升级就值了。”四、迁移过程中的两个“小插曲”插曲一一开始我们以为要改很多约束打开ApsConstraintProvider看到十几个约束方法心里咯噔一下。结果发现过滤逻辑一个都没变只有penalize()的写法变了而且 IDE 的批量替换 正则就能搞定大半插曲二担心 Shadow Variable 会不会崩我们有多个影子变量CustomShadowVariable担心 8.x 会有行为变化。实际验证下来监听器触发时机一致计算逻辑无误求解结果在多个数据集上完全一致五、我们怎么验证“没改坏”迁移完成后我们没有立刻上线而是做了三轮验证回归测试用生产脱敏数据跑 100 次求解对比 7.x 与 8.x 的求解结果和分数构成性能对比平均求解时间波动在 ±5% 以内GC 行为无明显变化异常注入模拟并发提交、服务重启验证 SolverManager 行为是否一致最终结论是这次升级没有改变 APS 的任何业务语义。六、回头看这次迁移的价值是什么如果只是为了“修那个偶发线程卡死”我们其实可以只加 JVM 参数。但我们还是做了 8.x 的迁移原因有三把“隐患”往前挪了一步7.x 是死胡同8.x 至少还有社区参考为 Timefold 铺路8.x 的 API 更接近 Timefold将来迁移成本更低团队信心大家亲手改过知道“哪里会变、哪里不变”七、一句话总结从 7.x 到 8.x不是一次“冒险”而是一次“低成本、高确定性的技术避险”。如果你也在犹豫要不要升我的建议是JDK 17 下能跑就先别动真要动就只动“必须动”的地方动完之后一定要验证而不是假设
延伸阅读

更多相关文章

2026/9/10 6:01:57

1Panel 服务器运维管理

1Panel 是一个现代化、开源的 Linux 服务器运维管理面板。它提供直观的 Web 图形界面,帮助用户轻松管理 Linux 服务器中的应用、网站、文件、数据库以及大语言模型(LLMs)等。 第一部分:1Panel 概述 一、什么是 1Panel?…

2026/9/3 1:15:45

一文搞懂出口摩洛哥必备COC认证全部要求

摩洛哥COC认证是清关的硬门槛,2025年起全面数字化。本文从法律要求、宗教禁忌、实操流程三方面拆解,帮出口商少走弯路,顺利通关。一、为什么非办不可?2020年6月起,电器、建材、玩具、纺织品等全品类强制要求COC&#x…

2026/9/12 16:35:52

从 0 到 1:mailcow Docker 邮件服务器完整部署指南

从 0 到 1:mailcow Docker 邮件服务器完整部署指南 【免费下载链接】mailcow-dockerized mailcow: dockerized - 🐮 🐋 💕 项目地址: https://gitcode.com/GitHub_Trending/ma/mailcow-dockerized 如果你想在自己的域名上…

2026/9/12 16:35:52

TradingAgents-CN 怎么配置股票基础信息每日定时同步任务?

TradingAgents-CN 怎么配置股票基础信息每日定时同步任务? 【免费下载链接】TradingAgents-CN 基于多智能体LLM的中文金融交易框架 - TradingAgents中文增强版 项目地址: https://gitcode.com/GitHub_Trending/tr/TradingAgents-CN 在 TradingAgents-CN 中&a…

2026/9/12 16:35:52

ESP32+WT3000TX工业级离线TTS方案实战

1. 为什么不用“联网调用云TTS API”?——从真实项目现场反推硬件选型逻辑 我第一次在客户现场看到这个需求时,对方工程师直接把手机递过来:“你试试,用我们现在的WiFi模块连上公司内网,调百度/阿里云TTS接口&#xff…

2026/9/12 2:05:33

超人会飞不算本事:系统稳定依赖清晰规则与边界设计

开头先不绕弯子。“#斯坦李吐槽dc 所以超人是无缘无故会飞的嘛哈哈哈哈哈哈哈锤哥真是技术人才啊!#雷神 #复联”这类调侃式短标题,第一波冲击力在于它把两个宇宙的角色塞进同一个吐槽箱里,但细想一下就能发现,它真正碰到的根本不是…

2026/9/12 3:55:12

超人VS蜘蛛侠:拆解超级IP的影响力与传播方法论

把“蜘蛛侠 vs 超人”放在 CSDN 上聊,可能很多人第一反应是走错片场了。但如果把这两个角色看成“两个持续运营了 80 多年的文化产品”,你会发现,这场比较本质上是两个不同 IP 策略的长期结果对比:超人赢在定义了整个超级英雄题材…

2026/9/12 10:09:03

基于CNN的调制信号识别:MATLAB实现时频图分类实战

简介:本资源是一套面向通信工程与信号处理方向学习者、研究者的深度学习实践方案,聚焦调制信号自动检测与识别这一典型无线通信任务,解决传统方法依赖人工特征、低信噪比下性能下降等痛点。压缩包共12个文件(10.73MB)&…

2026/9/12 0:04:17

MATLAB仿生优化框架:长鼻浣熊算法多策略融合实现

简介:本资源是一份面向智能优化算法研究者与MATLAB初学者的仿生智能算法实践代码包,聚焦于长鼻浣熊优化算法(COA)的多策略改进与性能验证。针对传统COA易陷局部最优、收敛精度不足等问题,作者融合Circle映射初始化提升…

2026/9/12 0:04:17

【JAVA毕设源码分享】基于 JavaWeb 的校园一卡通管理系统的设计与实现 基于 JavaWeb 的校园卡业务管理系统(程序+文档+代码讲解+一条龙定制)

博主介绍:✌️码农一枚 ,专注于大学生项目实战开发、讲解和毕业🚢文撰写修改等。全栈领域优质创作者,博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java、小程序技术领域和毕业项目实战 ✌️技术范围:&am…

2026/9/12 0:04:17

【JAVA毕设源码分享】基于 Java 的图书馆借阅管理平台的搭建与实现 基于 Java 的图书馆综合管理系统(程序+文档+代码讲解+一条龙定制)

博主介绍:✌️码农一枚 ,专注于大学生项目实战开发、讲解和毕业🚢文撰写修改等。全栈领域优质创作者,博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java、小程序技术领域和毕业项目实战 ✌️技术范围:&am…

2026/9/12 6:29:36

USB Type-C PCB布局分区设计:电源、高速信号与PD协议全攻略

做硬件这行,Type-C接口算是典型的“看着简单,做起来全坑”的东西。光引脚就24个,高低速信号、电源、控制线全部塞在一个小小的连接器里,如果PCB布局不做规划,打样回来基本就是“插上没反应”、“高速掉线”、“静电一打…

2026/9/12 14:32:17

系统编程学习原型如何补齐稳定性边界

系统编程学习原型如何补齐稳定性边界预算有限时&#xff0c;我先优化明显多余的复制&#xff0c;而不是猜测性地换容器。用借用传递只读数据通常就能减少分配&#xff1a; fn parse(line: &str) -> Result<Item, Error> { /* ... */ }用基准确认热点确实在分配&am…

2026/9/12 6:37:43

雨花区哪家财务公司代理记账比较好?

在雨花区&#xff0c;企业处理财税事务常常面临诸多挑战&#xff0c;选择一家靠谱的财务公司至关重要。湖南巨勤财务管理咨询有限公司就是本地正规实体财税服务机构&#xff0c;深耕本地工商财税行业多年&#xff0c;熟悉当地工商局、税务局最新政策与申报流程。主营公司注册、…

还想了解更多?直接咨询顾问

免费诊断 + 免费方案 + 透明报价。

全国咨询热线400-8866-253
免费获取方案
咨询二维码