You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Quartz Cron调度器在指定时间被重复触发两次问题排查

解决Quartz Cron调度器重复触发的问题

你的Quartz Cron调度器每天13:00被触发两次,我先梳理下你的配置和代码,再分析几个常见的原因及对应的解决办法:

你的配置与代码

Spring Bean配置

<bean id="runMeTask" class="com.ascent.fieldomobify.cornScheduler.RunMeTask"/>
<bean name="runMeJob" class="org.springframework.scheduling.quartz.JobDetailBean">
    <property name="jobClass" value="com.ascent.fieldomobify.cornScheduler.RunMeJob" />
    <property name="jobDataAsMap">
        <map>
            <entry key="runMeTask" value-ref="runMeTask" />
        </map>
    </property>
</bean>
<bean id="cronTrigger" class="org.springframework.scheduling.quartz.CronTriggerBean">
    <property name="jobDetail" ref="runMeJob"/>
    <property name="cronExpression" value="0 0 13 * * ?" />
</bean>
<bean class="org.springframework.scheduling.quartz.SchedulerFactoryBean">
    <property name="triggers">
        <list>
            <ref bean="cronTrigger" />
        </list>
    </property>
</bean>

RunMeJob实现类

public class RunMeJob extends QuartzJobBean {
    private RunMeTask runMeTask;

    public void setRunMeTask(RunMeTask runMeTask) {
        this.runMeTask = runMeTask;
    }

    protected void executeInternal(JobExecutionContext context) throws JobExecutionException {
        try {
            runMeTask.printMe();
        } catch (ParseException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }
}

RunMeTask实现类

public class RunMeTask{
    @Autowired
    WorkOrderController workorderContoller;

    public void setWorkorderContoller(WorkOrderController workorderContoller) {
        this.workorderContoller = workorderContoller;
    }

    public void printMe() throws ParseException {
        workorderContoller.printSysOut();
    }
}

常见原因及解决办法

1. Spring容器重复初始化

这是最常见的坑!比如在Web应用的web.xml里,你可能同时配置了ContextLoaderListener和DispatcherServlet,且两者的配置文件都扫描了调度相关的Bean,导致整个调度器被实例化两次,自然会触发两次任务。

解决办法:

  • 拆分配置职责:让ContextLoaderListener负责加载业务Bean、调度Bean这类非MVC组件,DispatcherServlet只负责扫描控制器(Controller)相关的Bean;
  • 或者在其中一个配置文件里通过exclude-filter排除调度Bean的扫描,避免重复创建。

2. Job/Trigger被重复注册

检查项目中是否有其他配置文件、或者Java Config代码也注册了同一个runMeJob或cronTrigger,导致调度器中存在两个完全相同的Trigger,到点就会同时触发。

解决办法:

  • 全局排查所有Spring配置,确保同一个Job和Trigger只定义一次;
  • 给SchedulerFactoryBean添加overwriteExistingJobs属性为true,重复注册的Job会被覆盖,不会重复触发:
    <bean class="org.springframework.scheduling.quartz.SchedulerFactoryBean">
        <property name="triggers">
            <list>
                <ref bean="cronTrigger" />
            </list>
        </property>
        <property name="overwriteExistingJobs" value="true" />
    </bean>
    

3. 集群环境下的并发执行

如果应用部署在集群多节点上,默认情况下每个节点的Quartz都会独立触发任务,就会导致同一时间多个节点执行同一个Job。

解决办法:

  • 配置Quartz使用JDBC JobStore:把Job和Trigger的状态存储到数据库中,集群节点会通过数据库锁保证只有一个节点执行任务;
  • 禁止Job并发执行:给JobDetail设置concurrent属性为false,避免同一个Job被同时执行:
    <bean name="runMeJob" class="org.springframework.scheduling.quartz.JobDetailBean">
        <property name="jobClass" value="com.ascent.fieldomobify.cornScheduler.RunMeJob" />
        <property name="jobDataAsMap">
            <map>
                <entry key="runMeTask" value-ref="runMeTask" />
            </map>
        </property>
        <property name="concurrent" value="false" />
    </bean>
    

4. 时区问题导致的重复触发

你的Cron表达式0 0 13 * * ?本身是正确的,但如果Quartz使用的时区和预期不一致(比如夏令时切换),可能会出现一天内触发两次的情况。

解决办法:

  • 给SchedulerFactoryBean明确指定时区,比如国内使用Asia/Shanghai:
    <bean class="org.springframework.scheduling.quartz.SchedulerFactoryBean">
        <property name="triggers">
            <list>
                <ref bean="cronTrigger" />
            </list>
        </property>
        <property name="timeZone" value="Asia/Shanghai" />
    </bean>
    

内容的提问来源于stack exchange,提问作者Prashant

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.28 06:31:05