quartz中需显式抛出new jobexecutionexception(e, true)实现立即重试;必须配合@disallowconcurrentexecution确保串行,且需自行控制重试次数防死循环。

在 Quartz 中,Job 执行过程中若直接 throw 普通异常(如 RuntimeException 或检查型异常),Quartz 默认会将其包装为 JobExecutionException 并终止当前执行——但不会自动设置 refireImmediately = true。要实现“立即重试”,必须显式抛出带有该标志的 JobExecutionException。
捕获异常后手动构造 JobExecutionException
Quartz 的 Job.execute(JobExecutionContext) 方法允许且鼓励你抛出 JobExecutionException 来控制调度行为。关键在于:不要让原始异常向上穿透,而应在 catch 块中主动封装。
- 用
new JobExecutionException(cause, true)构造,第二个参数即refireImmediately -
cause可以是原始异常(如IOException、NullPointerException),便于日志和排查 - 若无需立即重试,传
false或使用单参构造器(默认false)
典型写法示例
以下是在 Job 中处理网络调用失败并触发立即重试的常见模式:
Java JDK 25 来自 OpenJDK 官方归档,版本为 JDK 25,本条下载地址已指向官方 Windows x64 zip 安装包直链,适合调试旧项目或兼容旧版 Java 运行环境。
public class MyJob implements Job {
@Override
public void execute(JobExecutionContext context) throws JobExecutionException {
try {
callExternalService(); // 可能抛出 RuntimeException 或 checked exception
} catch (IOException e) {
// 网络临时故障,立即重试
throw new JobExecutionException(e, true);
} catch (Exception e) {
// 其他不可恢复错误(如数据格式错误),不重试
throw new JobExecutionException(e, false);
}
}
}
注意 refireImmediately 的实际效果
设置 refireImmediately = true 表示 Quartz 会立刻重新触发同一 Job 实例(不等待下次调度时间),但需满足前提:
- Job 类必须实现
Stateful(已废弃)或更推荐:使用@DisallowConcurrentExecution注解确保串行执行 - 若 Job 正在并发执行中,即使设了
true,Quartz 也不会强行中断或并发重试 - 重试无次数限制,需在业务逻辑中加计数或退避,避免死循环
替代方案:通过 JobDataMap 控制重试次数
可在 Job 执行前从 JobDataMap 获取已重试次数,达到阈值后改为抛出普通异常或 new JobExecutionException(..., false):
- 首次执行时,
context.getJobDetail().getJobDataMap().put("retryCount", 0) - 每次异常重试前递增计数,并检查是否超限
- 避免无限重试导致线程阻塞或资源耗尽
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










