乐趣区

SpringBoot系列Spring-Boot集成定时任务Quartz

一、关于 Quartz

Quartz 是 OpenSymphony 开源组织在 Job scheduling 领域又一个开源项目,它可以与 J2EE 与 J2SE 应用程序相结合也可以单独使用。在 java 企业级应用中,Quartz 是使用最广泛的定时调度框架。

在 Quartz 中的主要概念:

  • Scheduler:调度任务的主要 API
  • ScheduleBuilder:用于构建 Scheduler,例如其简单实现类 SimpleScheduleBuilder
  • Job:调度任务执行的接口,也即定时任务执行的方法
  • JobDetail:定时任务作业的实例
  • JobBuilder:关联具体的 Job,用于构建 JobDetail
  • Trigger:定义调度执行计划的组件,即定时执行
  • TriggerBuilder:构建 Trigger

一、Quartz 演示示例

在 SpringBoot 中,我们需要引入 quartz 的依赖。

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

<!--quartz 定时调度依赖 -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-quartz</artifactId>
</dependency>

首先定义定时具体执行逻辑 Job,创建类 QuartzJob1,这里集继承 QuartzJobBean 实现 executeInternal 即可,该方法即定时执行任务逻辑,这里简单打印了下当前时间。

public class QuartzJob1 extends QuartzJobBean {

    @Override
    protected void executeInternal(JobExecutionContext jobExecutionContext) throws JobExecutionException {SimpleDateFormat sdf=new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        System.out.println("QuartzJob1----" + sdf.format(new Date()));
    }

}

然后创建 QuartzConfig,接着定义 JobDetail,JobDetail 由 JobBuilder 构建,同时关联了任务 QuartzJob1。

@Configuration
public class QuartzConfig {

    @Bean
    public JobDetail jobDetail1(){return JobBuilder.newJob(QuartzJob1.class).storeDurably().build();
    }
    
}

最后我们需要定义定时调度 Trigger,简单实现类 SimpleScheduleBuilder 用于构建 Scheduler,TriggerBuilder 则用于构建 Trigger,

@Configuration
public class QuartzConfig {

    @Bean
    public JobDetail jobDetail1(){return JobBuilder.newJob(QuartzJob1.class).storeDurably().build();
    }

    @Bean
    public Trigger trigger1(){SimpleScheduleBuilder scheduleBuilder = SimpleScheduleBuilder.simpleSchedule()
                .withIntervalInSeconds(1) // 每一秒执行一次
                .repeatForever(); // 永久重复,一直执行下去
        return TriggerBuilder.newTrigger()
                .forJob(jobDetail1())
                .withSchedule(scheduleBuilder)
                .build();}
    
}

这样一个 Quartz 定时任务就配置完成了。

其实 Job 的定义也可以使用内部类,这样可以省去 Job 类的创建,例如下面定时任务 2 jobDetail2 和 trigger2。

@Bean
public JobDetail jobDetail2(){QuartzJobBean quartzJob2 = new QuartzJobBean() {
        @Override
        protected void executeInternal(JobExecutionContext jobExecutionContext) throws JobExecutionException {SimpleDateFormat sdf=new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
            System.out.println("内部类 quartzJob2----" + sdf.format(new Date()));
        }
    };
    return JobBuilder.newJob(quartzJob2.getClass()).storeDurably().build();
}

@Bean
public Trigger trigger2(){
    //JobDetail 的 bean 注入不能省略
    //JobDetail jobDetail3 = JobBuilder.newJob(QuartzJob2.class).storeDurably().build();
    SimpleScheduleBuilder scheduleBuilder = SimpleScheduleBuilder.simpleSchedule()
            .withIntervalInSeconds(2) // 每 2 秒执行一次
            .repeatForever(); // 永久重复,一直执行下去
    return TriggerBuilder.newTrigger()
            .forJob(jobDetail2())
            .withSchedule(scheduleBuilder).build();}

启动程序,我们就可以看到控制台的时间输出了。

同时 Quartz 是支持数据持久化的,可以将定时调度信息持久化到数据库。

选择持久化到数据库,我们需要创建对应的表,建表语句可以在 Quartz 官网进行下载,解压后在 docsdbTables 目录下寻找对应数据库的 SQL 脚本。

为了方便,我也将该文件放在了项目源码 resources 里。

操作数据库,我们引入相关的依赖。若有 ORM 框架,例如 mybatis,hibernate 或者 jpa,则无需再引入 jdbc 依赖。

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

<!--druid 连接池 -->
<dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>druid-spring-boot-starter</artifactId>
    <version>1.1.10</version>
</dependency>

<!--jdbc 依赖 -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>

在 application.yml 配置文件中,我们对 quartz 持久化方式进行声明。

server:
  port: 10900

spring:
  profiles:
    active: dev
  quartz:
    job-store-type: jdbc #持久化到数据库
    properties:
      org:
        quartz:
          datasource:
            # 新版驱动从 com.mysql.jdbc.Driver 变更为 com.mysql.cj.jdbc.Driver
            driver-class-name: com.mysql.cj.jdbc.Driver
            # 数据源需要添加时间标准和指定编码格式解决乱码 You must configure either the server or JDBC driver (via the serverTimezone configuration property) to use a more specifc time zone value if you want to utilize time zone support.
            url: jdbc:mysql://localhost:3306/springboot?useUnicode=true&characterEncoding=UTF-8&serverTimezone=UTC
            username: root
            password: 1234
          scheduler:
            instancName: clusteredScheduler
            instanceId: AUTO
          jobStore:
            class: org.quartz.impl.jdbcjobstore.JobStoreTX
            driverDelegateClass: org.quartz.impl.jdbcjobstore.StdJDBCDelegate #StdJDBCDelegate 说明支持集群
            tablePrefix: QRTZ_
            isClustered: true
            clusterCheckinInterval: 1000
            useProperties: false
          threadPool:
            class: org.quartz.simpl.SimpleThreadPool
            threadCount: 20
            threadPriority: 5

这里主要就是 job-store-type: jdbc,表示持久化到数据库,然后就是数据源,由于该演示项目没有其他 ORM 的数据源,所以这里将数据源信息定义在了 quartz 节点下的 datasource 节点,如果已经存在,可使用同一个属性配置,当然最关键的是 QuartzDataSource 声明。

这里关键的是 @QuartzDataSource,这个要和项目中已经存在的数据源区分开。

//Error:EmbeddedDatabaseType class not found,Druid 数据源初始化需要引入 spring-jdbc 依赖,JPA 或 mybatis 依赖已经包含该依赖
@Bean
@QuartzDataSource
@ConfigurationProperties(prefix = "spring.quartz.properties.org.quartz.datasource")
DataSource quartzDataSource(){return DruidDataSourceBuilder.create().build();}

这样持久化就已经配置好了,我们执行 sql,再启动项目,启动完成后,我们可以看到数据库中已经有我们的定时调度数据了。

源码地址:https://github.com/imyanger/s…

退出移动版