浅谈Java之开源任务调度(Quartz )

一、Quartz 核心概念

概念 说明
Scheduler 调度器,负责管理任务和触发器的执行
Job 任务接口,定义需要执行的具体逻辑(实现 execute 方法)
JobDetail 任务的元数据(Job 的配置信息,如名称、组、关联的 Job 类)
Trigger 触发器,定义任务执行的时间规则(如 Cron 表达式、固定间隔等)
JobStore 任务存储方式(内存或数据库持久化)
ThreadPool 线程池配置,控制任务执行的并发性

二、Spring Boot 整合 Quartz

1. 添加依赖
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-quartz</artifactId>
</dependency>

2. 定义 Job 类

实现 Job 接口,定义任务逻辑:

public class MyJob implements Job {
    @Override
    public void execute(JobExecutionContext context) {
        System.out.println("Job executed at: " + new Date());
    }
}

3. 配置 Quartz

创建 QuartzConfig 类,定义 JobDetail 和 Trigger

@Configuration
public class QuartzConfig {

    // 定义 JobDetail
    @Bean
    public JobDetail myJobDetail() {
        return JobBuilder.newJob(MyJob.class)
                .withIdentity("myJob", "group1")
                .storeDurably() // 持久化任务
                .build();
    }

    // 定义 Trigger(Cron 表达式)
    @Bean
    public Trigger myJobTrigger() {
        return TriggerBuilder.newTrigger()
                .forJob(myJobDetail())
                .withIdentity("myTrigger", "group1")
                .withSchedule(CronScheduleBuilder.cronSchedule("0/5 * * * * ?")) // 每 5 秒执行
                .build();
    }
}

三、动态管理任务

Quartz 支持运行时动态增删改任务:

1. 注入 Scheduler
@Autowired
private Scheduler scheduler;

2. 动态添加任务
public void addDynamicJob(String jobName, String group, String cron) throws SchedulerException {
    JobDetail jobDetail = JobBuilder.newJob(MyJob.class)
            .withIdentity(jobName, group)
            .build();

    Trigger trigger = TriggerBuilder.newTrigger()
            .withIdentity(jobName + "Trigger", group)
            .withSchedule(CronScheduleBuilder.cronSchedule(cron))
            .build();

    scheduler.scheduleJob(jobDetail, trigger);
}

3. 暂停/恢复任务
// 暂停任务
scheduler.pauseJob(JobKey.jobKey(jobName, group));

// 恢复任务
scheduler.resumeJob(JobKey.jobKey(jobName, group));

四、持久化任务到数据库

Quartz 支持将任务存储到数据库,避免任务丢失:

1. 添加数据库配置

在 application.properties 中配置:

# 使用 JDBC JobStore
spring.quartz.job-store-type=jdbc

# 配置数据源
spring.datasource.url=jdbc:mysql://localhost:3306/quartz
spring.datasource.username=root
spring.datasource.password=123456
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver

# 初始化 Quartz 表结构
spring.quartz.jdbc.initialize-schema=always
2. 初始化数据库表

Quartz 需要特定的表结构,SQL 文件可在 Quartz 官网 下载。

五、集群配置

在分布式环境中,Quartz 集群通过数据库锁实现任务协调:

# 启用集群模式
spring.quartz.properties.org.quartz.jobStore.isClustered=true
spring.quartz.properties.org.quartz.jobStore.clusterCheckinInterval=20000
spring.quartz.properties.org.quartz.scheduler.instanceId=AUTO

六、常见问题

1. Job 类无法序列化
  • 原因:持久化到数据库时,Job 类需实现 Serializable

  • 解决:确保 Job 类实现 Serializable 接口。

2. 事务管理
  • 在 Job 中调用 Spring Bean 时,需确保事务生效。可以通过 @Transactional 注解或编程式事务。

七、完整示例

// Job 类
public class EmailJob implements Job {
    @Override
    public void execute(JobExecutionContext context) {
        // 发送邮件的逻辑
        System.out.println("Sending email at: " + new Date());
    }
}

// 动态任务管理
@Service
public class JobService {
    @Autowired
    private Scheduler scheduler;

    public void scheduleEmailJob(String cron) throws SchedulerException {
        JobDetail jobDetail = JobBuilder.newJob(EmailJob.class)
                .withIdentity("emailJob", "notification")
                .build();

        Trigger trigger = TriggerBuilder.newTrigger()
                .withIdentity("emailTrigger", "notification")
                .withSchedule(CronScheduleBuilder.cronSchedule(cron))
                .build();

        scheduler.scheduleJob(jobDetail, trigger);
    }
}

八、Quartz vs Spring @Scheduled

特性 Quartz Spring @Scheduled
任务持久化 ✅ 支持 ❌ 仅内存
分布式集群 ✅ 支持 ❌ 不支持
动态任务管理 ✅ 支持 ❌ 需自行实现
复杂度 较高 简单
适用场景 企业级复杂调度需求 简单定时任务