精通Quartz-01入门介绍和简单示例

1,203 阅读4分钟

1 Quartz 简介

Quartz 是基于Java 实现的一个开源的调度框架, 是开源组织OpenSymphony 的产品。该项目于 2009 年被 Terracotta 收购,目前是 Terracotta 旗下的一个项目。官方网站:www.quartz-scheduler.org/ 。

本人在产品开发中使用的是版本 2.3.0,因此本文内容也基于该版本。

2 Quartz功能及特点

运行环境 

Quartz 能通过JVM独立运行

 Quartz 能在一个应用服务器里被实例化(或servlet容器), 并且可以作为XA事务的一部分来运行

 Quartz 能被集群化部署运行, 也可以单机方式运行

任务调度

任务有多种调度方式, 非常灵活:

  • 指定按某个时间间隔无限循环,例,每3分钟,每30秒
  • 指定到一天的某个时间点(精确到毫秒级), 例,每天的01:00:00, 每天的17:25:30
  • 指定只在一个固定时间点运行,例 2019-05-22 13:52:20
  • 通过Calendar排除某些时间 (例如节假日)
  • 循环重复的更灵活配置等等

任务执行

  • 任务可以是任何实现Job接口的Java类。一个任务可以有多种调度方式,任务与调度之间是解耦的,可自由组合。

任务持久化

  • 可以通过配置JobStoreCMT或JobStoreTX,可以实现任务的持久化。
  • 通过配置RAMJobStore, 可以将任务和触发器存储在内存里,运行性能更高。

事务

  • 使用JobStoreCMT(JDBCJobStore的子类),Quartz任务能作为JTA事务的一部分运行。

集群

开启集群模式部署运行后,系统具有集群的通用特性

  • Fail-over  
  • Load balancing  

监听器和插件

  • 通过实现一个或多个监听接口,应用程序能捕捉调度事件来监控或控制任务/触发器的行为。
  • 插件机制可以给Quartz增加功能,例如保持任务执行的历史记录,或从一个定义好的文件里加载任务和触发器。
  • Quartz 在运行过程中,很多地方都会回调监听器和插件。

容易与Spring集成

作为 Spring 默认的调度框架,Quartz 很容易与 Spring 集成

3 核心元素

Quartz 核心元素之间的关系如下图所示:

图 1. Quartz 核心元素关系图

图 1. Quartz 核心元素关系图


Quartz 任务调度的核心元素是 scheduler, trigger 和 job,其中 trigger 和 job 是任务调度的元数据, scheduler 是实际执行调度的控制器。scheduler 由 schedulerFactory创建, 默认实现是 StdSchedulerFactory。 

4.简单实例

本文为了方便介绍Quartz, 使用springboot来搭建项目,maven的pom文件如下:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>1.5.6.RELEASE</version>
        <!-- <relativePath></relativePath> -->
    </parent>
    <modelVersion>4.0.0</modelVersion>
    <artifactId>springboot-job</artifactId>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <!-- Quartz -->
        <dependency>
            <groupId>org.quartz-scheduler</groupId>
            <artifactId>quartz</artifactId>
            <version>2.3.0</version>
        </dependency>
        <!--代码更简洁-->
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>1.16.14</version>
            <scope>compile</scope>
        </dependency>
    </dependencies>
</project>

添加代码HelloJob

import org.quartz.*;
import org.quartz.impl.StdSchedulerFactory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.Calendar;
import java.util.concurrent.TimeUnit;

/**
 * 第一个Quartz Job
 * @author 深谷
 */
public class HelloJob implements Job {
    
    private static Logger log = LoggerFactory.getLogger(HelloJob.class);
    
    @Override
    public void execute(JobExecutionContext context) throws JobExecutionException {
        log.info("HelloJob 任务正在执行,当前时间: {}", Calendar.getInstance().getTime());
    }


    public static void main(String[] args) throws Throwable {
        SchedulerFactory factory = new StdSchedulerFactory();
        // 从工厂里面拿到一个scheduler实例
        Scheduler scheduler = factory.getScheduler();
        String name = "name_1";
        // 真正执行的任务并不是Job接口的实例,而是用反射的方式实例化的一个JobDetail实例
        JobDetail job = JobBuilder.newJob(HelloJob.class).withIdentity(name, null).build();
        // 定义一个触发器,调度策略是每隔30秒执行一次
        CronScheduleBuilder cronScheduleBuilder = CronScheduleBuilder.cronSchedule("0/30 * * * * ?").withMisfireHandlingInstructionDoNothing();
        Trigger trigger = TriggerBuilder.newTrigger().withIdentity(name, null).withSchedule(cronScheduleBuilder).build();
        // 将任务和Trigger放入scheduler
        scheduler.scheduleJob(job, trigger);
        scheduler.start();
        // 休眠一分钟,以便任务可以执行
        TimeUnit.MINUTES.sleep(1L);
        // scheduler结束
        scheduler.shutdown(true);
    }
}

运行一下,看一下输出

11:36:08.021 logback [main] INFO  org.quartz.core.QuartzScheduler[initialize-294] - Scheduler meta-data: Quartz Scheduler (v2.3.0) 'DefaultQuartzScheduler' with instanceId 'NON_CLUSTERED'
  Scheduler class: 'org.quartz.core.QuartzScheduler' - running locally.
  NOT STARTED.
  Currently in standby mode.
  Number of jobs executed: 0
  Using thread pool 'org.quartz.simpl.SimpleThreadPool' - with 10 threads.
  Using job-store 'org.quartz.simpl.RAMJobStore' - which does not support persistence. and is not clustered.

11:36:08.021 logback [main] INFO  org.quartz.impl.StdSchedulerFactory[instantiate-1362] - Quartz scheduler 'DefaultQuartzScheduler' initialized from default resource file in Quartz package: 'quartz.properties'
11:36:08.021 logback [main] INFO  org.quartz.impl.StdSchedulerFactory[instantiate-1366] - Quartz scheduler version: 2.3.0
11:36:08.035 logback [main] INFO  org.quartz.core.QuartzScheduler[start-547] - Scheduler DefaultQuartzScheduler_$_NON_CLUSTERED started.
11:36:30.017 logback [DefaultQuartzScheduler_Worker-1] INFO  com.ff.job.HelloJob[execute-21] - HelloJob 任务正在执行,当前时间: Thu Dec 06 11:36:30 CST 2018
11:37:00.004 logback [DefaultQuartzScheduler_Worker-2] INFO  com.ff.job.HelloJob[execute-21] - HelloJob 任务正在执行,当前时间: Thu Dec 06 11:37:00 CST 2018
11:37:08.036 logback [main] INFO  org.quartz.core.QuartzScheduler[shutdown-666] - Scheduler DefaultQuartzScheduler_$_NON_CLUSTERED shutting down.