Quartz 整合 Spring Boot

尽意
2024-10-19 / 0 评论 / 14 阅读 / 正在检测是否收录...
温馨提示:
本文最后更新于2024年10月19日,已超过95天没有更新,若内容或图片失效,请留言反馈。

1. 项目初始化

1.1 引入依赖

首先,我们需要在 Spring Boot 项目中引入 Quartz 相关的依赖。

对于 Maven 项目,编辑 pom.xml 文件,添加如下依赖:

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-quartz</artifactId>
</dependency>

对于 Gradle 项目,则添加如下依赖:

implementation 'org.springframework.boot:spring-boot-starter-quartz'

1.2 添加数据库支持(可选)

如果我们打算让 Quartz 任务持久化(任务信息存储到数据库中),则需要添加数据库驱动。例如,使用 MySQL 数据库时,添加以下依赖:

<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    <scope>runtime</scope>
</dependency>

这样我们就可以通过 Quartz 将任务存储在数据库中,保证任务在调度器重启后仍然存在。

2. 创建 Quartz 任务

2.1 创建一个简单的 Job

在 Quartz 中,每个任务都由一个 Job 类来表示。Job 是 Quartz 的核心接口,它只有一个 execute() 方法,当触发器触发任务时,该方法将会被调用。

我们首先创建一个简单的任务类 MyQuartzJob,该任务每次被触发时会输出 "Hello, Quartz!" 以及当前的时间。

import org.quartz.Job;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
import org.springframework.stereotype.Component;

@Component
public class MyQuartzJob implements Job {

    @Override
    public void execute(JobExecutionContext context) throws JobExecutionException {
        System.out.println("执行任务: Hello, Quartz! 当前时间: " + System.currentTimeMillis());
    }
}

2.2 解释

  • Job 接口要求实现 execute(JobExecutionContext context) 方法,这个方法将在任务触发时被 Quartz 调度器调用。
  • JobExecutionContext 提供了调度任务的上下文信息,如任务数据、触发器信息等。
  • 我们使用了 @Component 注解将该任务类注册为 Spring 的 Bean,便于在配置中注入和管理。

3. 配置 Quartz 调度任务

为了使任务能够被 Quartz 调度器调度,我们需要配置 JobDetailTriggerJobDetail 定义了任务的具体信息,而 Trigger 定义了任务的触发规则(如时间间隔、执行次数等)。

3.1 基于时间间隔的 SimpleTrigger

以下是一个配置类 QuartzConfig,它定义了一个每 5 秒触发一次的任务。

import org.quartz.JobDetail;
import org.quartz.Trigger;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.quartz.JobDetailFactoryBean;
import org.springframework.scheduling.quartz.SimpleTriggerFactoryBean;

@Configuration
public class QuartzConfig {

    // 配置 JobDetail
    @Bean
    public JobDetailFactoryBean jobDetail() {
        JobDetailFactoryBean factoryBean = new JobDetailFactoryBean();
        factoryBean.setJobClass(MyQuartzJob.class);  // 绑定 Job 类
        factoryBean.setDescription("这是一个示例 Quartz Job");
        factoryBean.setDurability(true);  // 任务持久化
        return factoryBean;
    }

    // 配置 Trigger(每 5 秒执行一次)
    @Bean
    public SimpleTriggerFactoryBean trigger(JobDetail jobDetail) {
        SimpleTriggerFactoryBean factoryBean = new SimpleTriggerFactoryBean();
        factoryBean.setJobDetail(jobDetail);  // 绑定任务
        factoryBean.setRepeatInterval(5000);  // 每 5 秒触发一次
        factoryBean.setRepeatCount(SimpleTriggerFactoryBean.REPEAT_INDEFINITELY);  // 无限重复执行
        return factoryBean;
    }
}

3.2 解释

  • JobDetailFactoryBean:用于定义 Quartz 的 JobDetail。它将指定的 Job 与任务元数据(如任务描述、持久化策略等)绑定。
  • SimpleTriggerFactoryBean:用于配置一个简单触发器(SimpleTrigger),我们可以设置触发间隔时间(单位:毫秒)以及重复执行次数。在这个示例中,任务会每隔 5 秒重复执行一次,且无限次重复。

3.3 CronTrigger 的使用

如果需要更复杂的触发条件,比如按照每天某个时间点或每周的某些特定时刻触发任务,Quartz 提供了 CronTriggerCronTrigger 允许我们通过 Cron 表达式精确地控制任务的调度时间。

import org.quartz.JobDetail;
import org.springframework.context.annotation.Bean;
import org.springframework.scheduling.quartz.CronTriggerFactoryBean;
import org.springframework.scheduling.quartz.JobDetailFactoryBean;

@Configuration
public class QuartzCronConfig {

    // 配置 JobDetail
    @Bean
    public JobDetailFactoryBean cronJobDetail() {
        JobDetailFactoryBean factoryBean = new JobDetailFactoryBean();
        factoryBean.setJobClass(MyQuartzJob.class);
        factoryBean.setDescription("这是一个示例 Cron Quartz Job");
        factoryBean.setDurability(true);  // 任务持久化
        return factoryBean;
    }

    // 配置 CronTrigger(每 10 秒执行一次)
    @Bean
    public CronTriggerFactoryBean cronTrigger(JobDetail cronJobDetail) {
        CronTriggerFactoryBean factoryBean = new CronTriggerFactoryBean();
        factoryBean.setJobDetail(cronJobDetail);  // 绑定任务
        factoryBean.setCronExpression("0/10 * * * * ?");  // 每 10 秒触发一次
        return factoryBean;
    }
}

3.4 Cron 表达式解释

  • "0/10 * * * * ?":每隔 10 秒执行一次。Cron 表达式的格式是 "秒 分 时 日 月 星期 年(可选)"。这个表达式表示每分钟的第 0 秒开始,每 10 秒触发一次任务。

4. 使用 JobDataMap 传递参数

在实际应用中,任务往往需要使用外部数据。Quartz 提供了 JobDataMap,用于在任务执行时传递参数。

4.1 配置任务并传递参数

JobDetailFactoryBean 中,我们可以通过 setJobDataAsMap() 方法传递参数:

@Bean
public JobDetailFactoryBean jobDetailWithParams() {
    JobDetailFactoryBean factoryBean = new JobDetailFactoryBean();
    factoryBean.setJobClass(MyQuartzJob.class);
    factoryBean.setDescription("带参数的 Quartz Job");
    factoryBean.setDurability(true);
    
    // 传递参数
    Map<String, Object> jobDataMap = new HashMap<>();
    jobDataMap.put("param1", "参数值1");
    factoryBean.setJobDataAsMap(jobDataMap);
    
    return factoryBean;
}

4.2 在 Job 中获取参数

execute() 方法中,我们可以通过 JobExecutionContext 获取传递的参数:

public class MyQuartzJob implements Job {

    @Override
    public void execute(JobExecutionContext context) throws JobExecutionException {
        String param1 = context.getMergedJobDataMap().getString("param1");
        System.out.println("执行任务,参数1: " + param1);
    }
}

JobDataMap 允许我们在任务执行时携带自定义数据,并在任务中访问这些数据。对于复杂的业务逻辑,这一特性非常实用。

5. 任务持久化(使用 JDBC)

Quartz 支持将任务信息持久化到数据库中,这对于任务调度器重启时继续执行未完成的任务非常重要。为了使用持久化功能,我们需要配置数据库,并让 Quartz 将任务和调度信息保存到数据库中。

5.1 创建数据库表

首先,你需要为 Quartz 创建数据库表。Quartz 官方提供了 SQL 脚本用于创建这些表。你可以在 Quartz 文档 中找到

5.2 配置 Quartz 使用数据库

application.propertiesapplication.yml 文件中,我们需要配置 Quartz 使用 JDBC 存储任务调度数据。

对于 application.properties

spring.quartz.job-store-type=jdbc  # 使用数据库存储
spring.quartz.jdbc.initialize-schema=always  # 自动创建表,生产环境中建议使用 validate
spring.quartz.properties.org.quartz.jobStore.driverDelegateClass=org.quartz.impl.jdbcjobstore.StdJDBCDelegate  # JDBC驱动代理
spring.datasource.url=jdbc:mysql://localhost:3306/quartz_db?useSSL=false&serverTimezone=UTC  # 数据库连接URL
spring.datasource.username=root  # 数据库用户名
spring.datasource.password=your_password  # 数据库密码

对于 application.yml

spring:
  quartz:
    job-store-type: jdbc  # 使用数据库存储
    jdbc:
      initialize-schema: always  # 自动创建表
    properties:
      org:
        quartz:
          jobStore:
            driverDelegateClass: org.quartz.impl.jdbcjobstore.StdJDBCDelegate  # JDBC代理
  datasource:
    url: jdbc:mysql://localhost:3306/quartz_db?useSSL=false&serverTimezone=UTC  # 数据库URL
    username: root  # 数据库用户名
    password: your_password  # 数据库密码

5.3 初始化数据库

Quartz 提供了内置的表结构,默认会在数据库中创建任务、触发器、锁等所需的表。配置 spring.quartz.jdbc.initialize-schema=always 可以让 Spring Boot 在启动时自动初始化这些表。你也可以手动执行 Quartz 提供的 SQL 脚本,这些脚本位于 Quartz 官方发布包的 docs/dbTables 目录下。

5.4 解释

  • job-store-type:指定 Quartz 如何存储任务信息。memory 表示将任务存储在内存中,jdbc 则表示将任务存储在数据库中。
  • driverDelegateClass:指定数据库驱动代理类。对于 MySQL,我们使用 StdJDBCDelegate,如果使用其他数据库(如 PostgreSQL),则需要根据数据库类型选择对应的代理类。
  • initialize-schema:控制是否在启动时自动创建 Quartz 需要的表。生产环境下应设置为 validate,以避免重复创建表。

5.5 测试任务持久化

当 Quartz 任务配置完成并启动时,所有的任务、触发器以及调度信息都会存储到配置的数据库中。你可以停止并重启应用程序,来验证任务的持久性。如果配置正确,任务调度器重新启动后,Quartz 将从数据库中恢复之前的任务调度信息并继续执行未完成的任务。

6. 任务并发控制

默认情况下,Quartz 会在多个线程中并发执行多个任务。如果你希望控制任务的并发执行,可以通过 @DisallowConcurrentExecution 注解来实现,确保同一个任务在同一时间只有一个实例在运行。

6.1 禁止并发执行

修改我们的 MyQuartzJob 类,添加 @DisallowConcurrentExecution 注解:

import org.quartz.DisallowConcurrentExecution;
import org.quartz.Job;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
import org.springframework.stereotype.Component;

@DisallowConcurrentExecution  // 禁止并发执行
@Component
public class MyQuartzJob implements Job {

    @Override
    public void execute(JobExecutionContext context) throws JobExecutionException {
        System.out.println("执行任务: Hello, Quartz! 当前时间: " + System.currentTimeMillis());
    }
}

6.2 解释

  • @DisallowConcurrentExecution:Quartz 提供的注解,用于确保在同一时间内同一任务(JobDetail)只能执行一次。如果该任务正在运行,新的任务不会并发执行。

7. 动态添加与删除任务

在实际应用中,我们可能需要根据某些业务规则动态地添加或删除定时任务。Quartz 支持动态管理任务,可以通过 Quartz 提供的 API 来实现任务的增删改查。

7.1 动态添加任务

以下是一个示例,用于动态添加任务:

import org.quartz.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

@Service
public class QuartzJobService {

    @Autowired
    private Scheduler scheduler;  // 注入 Quartz 的 Scheduler

    // 动态添加任务
    public void addJob(String jobName, String groupName, String cronExpression) throws SchedulerException {
        JobDetail jobDetail = JobBuilder.newJob(MyQuartzJob.class)
                                        .withIdentity(jobName, groupName)
                                        .build();

        CronTrigger trigger = TriggerBuilder.newTrigger()
                                            .withIdentity(jobName + "Trigger", groupName)
                                            .withSchedule(CronScheduleBuilder.cronSchedule(cronExpression))
                                            .build();

        scheduler.scheduleJob(jobDetail, trigger);  // 将任务和触发器注册到调度器
    }
}

7.2 动态删除任务

以下是动态删除任务的示例:

public void deleteJob(String jobName, String groupName) throws SchedulerException {
    JobKey jobKey = JobKey.jobKey(jobName, groupName);
    scheduler.deleteJob(jobKey);  // 删除指定的任务
}

7.3 调用示例

你可以通过 REST API 或者在服务启动时调用这些方法:

@RestController
@RequestMapping("/jobs")
public class JobController {

    @Autowired
    private QuartzJobService jobService;

    @PostMapping("/add")
    public String addJob(@RequestParam String jobName,
                         @RequestParam String groupName,
                         @RequestParam String cronExpression) {
        try {
            jobService.addJob(jobName, groupName, cronExpression);
            return "任务添加成功";
        } catch (SchedulerException e) {
            e.printStackTrace();
            return "任务添加失败";
        }
    }

    @DeleteMapping("/delete")
    public String deleteJob(@RequestParam String jobName,
                            @RequestParam String groupName) {
        try {
            jobService.deleteJob(jobName, groupName);
            return "任务删除成功";
        } catch (SchedulerException e) {
            e.printStackTrace();
            return "任务删除失败";
        }
    }
}

8. 总结

通过本教程,你已经学会了如何将 Quartz 整合到 Spring Boot 中,并实现以下功能:

  • 创建简单的定时任务。
  • 使用 SimpleTriggerCronTrigger 实现时间间隔和复杂调度的任务。
  • 通过 JobDataMap 向任务传递参数。
  • 实现任务的持久化,并将任务信息保存到数据库中。
  • 控制任务的并发执行,避免重复调度。
  • 动态添加和删除定时任务。

Quartz 强大的调度功能与 Spring Boot 的简洁配置相结合,使得我们可以轻松构建复杂的任务调度系统。在实际应用中,你可以根据业务需求进行进一步的自定义和优化,构建一个高度可扩展的调度系统。

2

评论 (0)

取消