Quartz学习笔记

Quartz学习笔记

⼀、概述

Quartz是⼀个开放源码的任务调度框架。Quartz功能强⼤,可以让你的程序在指定时间执⾏,也可以按照某⼀个频度执⾏,⽀持数据库、监听器、插件、集群等特性。
使⽤场景:定时消息推送、定时抢购、定时发送邮件、定时统计等。

官网:http://www.quartz-scheduler.org/

二、搭建简单的任务调度环境

1. 创建一个Maven项目,引入依赖jar

<dependency>
 	<groupId>org.quartz-scheduler</groupId>
 	<artifactId>quartz</artifactId>
 	<version>2.2.1</version>
	</dependency>
<dependency>
 	<groupId>org.quartz-scheduler</groupId>
	<artifactId>quartz-jobs</artifactId>
 	<version>2.2.1</version>
</dependency>

2. 创建任务类,定义任务内容

package com.demo.job;

import org.quartz.Job;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;

import java.util.Date;

public class MyJob implements Job {
    public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException {
        //输出系统当前时间
        System.out.println(new Date());
    }
}

3. 构建调度任务功能类

package com.demo.test;

import com.demo.job.MyJob;
import org.quartz.CronTrigger;
import org.quartz.JobDetail;
import org.quartz.Scheduler;
import org.quartz.SchedulerException;
import org.quartz.impl.StdSchedulerFactory;

import static org.quartz.CronScheduleBuilder.cronSchedule;
import static org.quartz.JobBuilder.newJob;
import static org.quartz.TriggerBuilder.newTrigger;

public class QuartzJobTest {
    public static void main(String[] args) {
        // 1. 获取调度器
        Scheduler scheduler = null;
        try {
            scheduler = StdSchedulerFactory.getDefaultScheduler();
        } catch (SchedulerException e) {
            e.printStackTrace();
        }
        // 2. 包装任务内容
        JobDetail jobDetail = newJob(MyJob.class)
                .withIdentity("job1", "group1")
                .build();
        // 3. 定义触发器
        CronTrigger trigger = newTrigger()
                .withIdentity("trigger1", "group1")
                .startNow()
                .withSchedule(cronSchedule("* * * * * ? *"))
                .build();

        // 4. 组装任务
        try {
            scheduler.scheduleJob(jobDetail,trigger);
        } catch (SchedulerException e) {
            e.printStackTrace();
        }
        // 5. 启动调度器,开始调度
        try {
            scheduler.start();
        } catch (SchedulerException e) {
            e.printStackTrace();
        }
    }
}

三、Quartz体系架构

Job

是⼀个接⼝,只定义⼀个⽅法execute(JobExecutionContext context),在实现接⼝的execute
⽅法中编写所需要定时执⾏的Job(任务), JobExecutionContext类提供了调度应⽤的⼀些信息。
Job运⾏时的信息保存在JobDataMap实例中。

JobDetail

JobDetail 定义的是任务数据,⽽真正的执⾏逻辑是在Job中。sheduler每次执⾏,都会根据
JobDetail创建⼀个新的Job实例

Trigger

是⼀个类,描述触发Job执⾏的时间触发规则。主要有SimpleTrigger和CronTrigger这两个⼦类。
当且仅当需调度⼀次或者以固定时间间隔周期执⾏调度,SimpleTrigger是最适合的选择;
⽽CronTrigger则可以通过Cron表达式定义出各种复杂时间规则的调度⽅案:如⼯作⽇周⼀到周
五的15:00~16:00执⾏调度等

Cron表达式的格式:秒 分 时 ⽇ ⽉ 周 年(可选)。

字段名允许的值允许的特殊字符
0-59, – * /
0-59, – * /
0-23, – * /
1-31, – * ? / L W C
1-12 or JAN-DEC, – * /
1-7 or SUN-SAT, – * ? / L C # MON FRI
年(可选字段)empty, 1970-2099, – * /

允许的特殊字符:

  1. “?”字符:表示不确定的值
  2. “,”字符:指定数个值
  3. “-”字符:指定⼀个值的范围
  4. “/”字符:指定⼀个值的增加幅度。n/m表示从n开始,每次增加m
  5. “L”字符:⽤在⽇表示⼀个⽉中的最后⼀天,⽤在周表示该⽉最后⼀个星期X
  6. “W”字符:指定离给定⽇期最近的⼯作⽇(周⼀到周五)
  7. “#”字符:表示该⽉第⼏个周X。6#3表示该⽉第3个周五(从周日开始,6代表周五)

Cron表达式范例:

  1. 每隔5秒执⾏⼀次:*/5 * * * * ?
  2. 每隔1分钟执⾏⼀次:0 */1 * * * ?
  3. 每天23点执⾏⼀次:0 0 23 * * ?
  4. 每天凌晨1点执⾏⼀次:0 0 1 * * ?
  5. 每⽉1号凌晨1点执⾏⼀次:0 0 1 1 * ?
  6. 每⽉最后⼀天23点执⾏⼀次:0 0 23 L * ?
  7. 每周星期天凌晨1点实⾏⼀次:0 0 1 ? * L
  8. 在26分、29分、33分执⾏⼀次:0 26,29,33 * * * ?
  9. 每天的0点、13点、18点、21点都执⾏⼀次:0 0 0,13,18,21 * * ?

Scheduler

代表⼀个Quartz的独⽴运⾏容器,Trigger和JobDetail可以注册到Scheduler中, 两者在Scheduler中拥有各⾃的组及名称, 组及名称是Scheduler查找定位容器中某⼀对象的依据,Trigger的组及名称必须唯⼀, JobDetail的组和名称也必须唯⼀(但可以和Trigger的组和名称相同,因为它们是不同类型的)。Scheduler定义了多个接⼝⽅法, 允许外部通过组及名称访问和控制容器中Trigger和JobDetail。

JobBulider

⽤于定义/构建已经定义了Job实例的JobDetail实例

TriggerBuilder

⽤于定义/构建Trigger实例。

四、Quartz与Spring集成

1. 创建Spring项目,引入依赖jar

<!-- quartz依赖 -->
<dependency>
 	<groupId>org.quartz-scheduler</groupId>
 	<artifactId>quartz</artifactId>
 	<version>2.2.1</version>
</dependency>
<dependency>
 	<groupId>org.quartz-scheduler</groupId>
 	<artifactId>quartz-jobs</artifactId>
 	<version>2.2.1</version>
</dependency>
<!--spring依赖-->
<dependency>
 	<groupId>org.springframework</groupId>
 	<artifactId>spring-context-support</artifactId>
 	<version>3.2.8.RELEASE</version>
</dependency>
<dependency>
 	<groupId>org.springframework</groupId>
 	<artifactId>spring-tx</artifactId>
 	<version>3.2.8.RELEASE</version>
</dependency>

2. 创建任务类,定义任务内容

package com.demo.job;

import org.quartz.Job;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;

import java.util.Date;

public class MyJob implements Job {
    public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException {
        //输出系统当前时间
        System.out.println(new Date());
    }
}

3. 创建并编写spring的配置文件

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">

    <!-- 创建JobDetail -->
    <bean id="jobDetail" class="org.springframework.scheduling.quartz.JobDetailFactoryBean">
        <!-- 指定任务类 -->
        <property name="jobClass" value="com.demo.job.MyJob"></property>
        <!-- 当Job在没有可以使⽤的trigger的情况下 不删除 -->
        <property name="durability" value="true"></property>
    </bean>

    <!-- 注意 spring quartz整合 ⼀个trigger只可以绑定⼀个JobDetail ⼀个jobDetail可以被多个Trigger所使⽤ -->
    <bean id="trigger" class="org.springframework.scheduling.quartz.CronTriggerFactoryBean">
        <!-- 绑定JobDetail -->
        <property name="jobDetail" ref="jobDetail"></property>
        <property name="cronExpression" value="0-30 * * * * ?"></property>
    </bean>
    <bean id="trigger1" class="org.springframework.scheduling.quartz.CronTriggerFactoryBean">
        <!--绑定JobDetail-->
        <property name="jobDetail" ref="jobDetail"></property>
        <property name="cronExpression" value="45-55 * * * * ?"></property>
    </bean>

    <!--注册trigger,进行任务调度 -->
    <bean id="scheduler" class="org.springframework.scheduling.quartz.SchedulerFactoryBean">
        <property name="triggers">
            <list>
                <ref bean="trigger"></ref>
                <ref bean="trigger1"></ref>
            </list>
        </property>
    </bean>
</beans>

五、Quartz与Spring Boot集成

1. 创建Spring Boot项目,引入依赖jar

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

2. 创建任务类,定义任务内容

package com.demo.job;

import org.quartz.Job;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;

import java.util.Date;

public class MyJob implements Job {
    public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException {
        //输出系统当前时间
        System.out.println(new Date());
    }
}

3. 创建controller

package com.demo.controller;

import com.demo.job.MyJob;
import org.quartz.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import static org.quartz.CronScheduleBuilder.cronSchedule;
import static org.quartz.JobBuilder.newJob;
import static org.quartz.TriggerBuilder.newTrigger;

@RestController
public class QuartzController {

    @Autowired
    private Scheduler scheduler;

    /**
     * 新增调度任务的方法
     * @return
     */
    @RequestMapping("/add")
    public String addJob(String jobName,String jobGroup,String triggerName,String triggerGroup,String cronExpression){
        try {
            //包装任务
            JobDetail jobDetail = newJob(MyJob.class).withIdentity(jobName,jobGroup).build();
            //创建触发器及触发规则
            Trigger trigger = newTrigger()
                    //指定触发规则 ,cronExpression为Cron表达式
                    .withSchedule(cronSchedule(cronExpression))
                    //指定触发器名称及所属组
                    .withIdentity(triggerName,triggerGroup)
                    //创建触发器
                    .build();
            //进行调度
            scheduler.scheduleJob(jobDetail,trigger);
            return "success";
        } catch (SchedulerException e) {
            e.printStackTrace();
        }
        return "fail";
    }
    /**
     * 暂停调度任务
     */
    @RequestMapping("/pause")
    public String pause(String jobName,String jobGroup){
        try {
            scheduler.pauseJob(JobKey.jobKey(jobName,jobGroup));
            return "success";
        } catch (SchedulerException e) {
            e.printStackTrace();
        }
        return "fail";
    }
    /**
     * 开始调度任务
     */
    @RequestMapping("/remuse")
    public String remuse(String jobName,String jobGroup){
        try {
            scheduler.resumeJob(JobKey.jobKey(jobName,jobGroup));
            return "success";
        } catch (SchedulerException e) {
            e.printStackTrace();
        }
        return "fail";
    }
}

六、存储⽅式

1. RAMJobStore和JDBCJobStore存储方式对比

类型优点缺点
RAMJobStore(默认)不要外部数据库,配置容易,运⾏速度快因为调度程序信息是存储在被分配给JVM的内存⾥⾯,所以,当应⽤程序停⽌运⾏时,所有调度信息将被丢失。另外因为存储到JVM内存⾥⾯,所以可以存储多少个Job和Trigger将会受到限制
JDBCJobStore⽀持集群,因为所有的任务信息都会保存到数据库中,可以控制事物,还有就是如果应⽤服务器关闭或者重启,任务信息都不会丢失,并且可以恢复因服务器关闭或者重启⽽导致执⾏失败的任务运⾏速度的快慢取决与连接数据库的快慢

2. 设置 JDBCJobStore

在应⽤程序中设置使⽤ JDBCJobStore 需要两步:

1. ⾸先必须创建作业仓库使⽤的数据库表

JDBCJobStore 与所有主流数据库都兼容,⽽且 Quartz 提供了⼀系列创建表的 SQL 脚本,能够简化设置过程。可以在 Quartz 发⾏包的 “docs/dbTables”⽬录中找到创建表的 SQL 脚本,使用对应的SQL脚本创建表:数据库表
>Quartz 发⾏包下载地址:链接:https://pan.baidu.com/s/1CZ1khHlRc9SyIul10uDNDQ 提取码:agjx

2. 创建quartz.properties配置文件,并定义⼀些属性
在 `quartz.properties`⽂件中指定 JDBCJobStore 属性
	org.quartz.threadPool.class = org.quartz.simpl.SimpleThreadPool
	org.quartz.threadPool.threadCount = 10
	org.quartz.threadPool.threadPriority = 5
	org.quartz.threadPool.threadsInheritContextClassLoaderOfInitializingThread = true
	# Using RAMJobStore
	## if using RAMJobStore, please be sure that you comment out the following
	## - org.quartz.jobStore.tablePrefix,
	## - org.quartz.jobStore.driverDelegateClass,
	## - org.quartz.jobStore.dataSource
	#org.quartz.jobStore.class = org.quartz.simpl.RAMJobStore
	# Using JobStoreTX
	## Be sure to run the appropriate script(under docs/dbTables) first to create tables
	org.quartz.jobStore.class = org.quartz.impl.jdbcjobstore.JobStoreTX
	# Configuring JDBCJobStore with the Table Prefix
	org.quartz.jobStore.tablePrefix = QRTZ_
	# Using DriverDelegate
	org.quartz.jobStore.driverDelegateClass = 	org.quartz.impl.jdbcjobstore.StdJDBCDelegate
	# Using datasource
	org.quartz.jobStore.dataSource = qzDS
	# Define the datasource to use
	org.quartz.dataSource.qzDS.driver = com.mysql.jdbc.Driver
	org.quartz.dataSource.qzDS.URL = jdbc:mysql://localhost:3306/quartz
	org.quartz.dataSource.qzDS.user = root
	org.quartz.dataSource.qzDS.password = root
	org.quartz.dataSource.qzDS.maxConnections = 30
3. 定义spring的配置文件spring-quartz.xml

在进行任务调度时加入以下配置,指定jdbcJobStore的配置文件:
<property name="configLocation" value="classpath:quartz.properties"></property>
完整的spring配置文件如下:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">

    <!-- 创建JobDetail -->
    <bean id="jobDetail" class="org.springframework.scheduling.quartz.JobDetailFactoryBean">
        <!-- 指定任务类 -->
        <property name="jobClass" value="com.demo.job.MyJob"></property>
        <!-- 当Job在没有可以使⽤的trigger的情况下 不删除 -->
        <property name="durability" value="true"></property>
    </bean>

    <!-- 注意 spring quartz整合 ⼀个trigger只可以绑定⼀个JobDetail ⼀个jobDetail可以被多个Trigger所使⽤ -->
    <bean id="trigger" class="org.springframework.scheduling.quartz.CronTriggerFactoryBean">
        <!-- 绑定JobDetail -->
        <property name="jobDetail" ref="jobDetail"></property>
        <property name="cronExpression" value="0-30 * * * * ?"></property>
    </bean>
    <bean id="trigger1" class="org.springframework.scheduling.quartz.CronTriggerFactoryBean">
        <!--绑定JobDetail-->
        <property name="jobDetail" ref="jobDetail"></property>
        <property name="cronExpression" value="45-55 * * * * ?"></property>
    </bean>

    <!--注册trigger ,进行任务调度 -->
    <bean id="scheduler" class="org.springframework.scheduling.quartz.SchedulerFactoryBean">
        <!-- 指定jdbcJobStore使用的配置文件 -->
        <property name="configLocation" value="classpath:quartz.properties"></property>
        <property name="triggers">
            <list>
                <ref bean="trigger"></ref>
                <ref bean="trigger1"></ref>
            </list>
        </property>
    </bean>
</beans>
4. 运行测试

jdbcJobstore的存储方式
可以看到数据库中有任务存储进去。

六、集群⽀持

1. 原理

虽然单个Quartz实例能给予你很好的Job调度能⼒,但它不能满⾜典型的企业需求,如可伸缩性、⾼可靠性。假如你需要故障转移的能⼒并能运⾏⽇益增多的 Job,Quartz集群势必成为你应⽤的⼀部分了。使⽤ Quartz 的集群能⼒可以更好的⽀持你的业务需求,并且即使是其中⼀台机器在最糟的时间崩溃了也能确保所有的 Job 得到执⾏。
⼀个 Quartz 集群中的每个节点是⼀个独⽴的 Quartz 应⽤,它⼜管理着其他的节点。意思是你必须对每个节点分别启动或停⽌。不像许多应⽤服务器的集群,独⽴的 Quartz 节点并不与另⼀其他的节点通信或是管理节点通信。Quartz 应⽤是通过数据库表来感知到另⼀应⽤的。
图:表示了每个节点直接与数据库通信,若离开数据库将对其他节点⼀⽆所知
quartz集群节点之间的关系图

2. 搭建集群

1. 创建quartz-cluster.properties配置文件
#==============================================================
#Configure Main Scheduler Properties
#==============================================================
org.quartz.scheduler.instanceName = quartzScheduler
org.quartz.scheduler.instanceId = AUTO

#==============================================================
#Configure JobStore
#==============================================================
org.quartz.jobStore.class = org.quartz.impl.jdbcjobstore.JobStoreTX
org.quartz.jobStore.driverDelegateClass = org.quartz.impl.jdbcjobstore.StdJDBCDelegate
org.quartz.jobStore.tablePrefix = QRTZ_
org.quartz.jobStore.isClustered = true
org.quartz.jobStore.clusterCheckinInterval = 3000  
org.quartz.jobStore.dataSource = myDS

#==============================================================
#Configure DataSource
#==============================================================
org.quartz.dataSource.myDS.driver = com.mysql.jdbc.Driver
org.quartz.dataSource.myDS.URL = jdbc:mysql://localhost:3306/quartz?useUnicode=true&amp;characterEncoding=UTF-8
org.quartz.dataSource.myDS.user = root
org.quartz.dataSource.myDS.password = root
org.quartz.dataSource.myDS.maxConnections = 30

#==============================================================
#Configure ThreadPool
#==============================================================
org.quartz.threadPool.class = org.quartz.simpl.SimpleThreadPool
org.quartz.threadPool.threadCount = 5
org.quartz.threadPool.threadPriority = 5
org.quartz.threadPool.threadsInheritContextClassLoaderOfInitializingThread = true
2. 创建spring-quartz.xml配置文件

在进行任务调度时加入以下配置,指定使用集群的配置文件:
<property name="configLocation" value="classpath:quartz-cluster.properties"></property>
完整的spring配置文件如下:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">

    <!-- 创建JobDetail -->
    <bean id="jobDetail" class="org.springframework.scheduling.quartz.JobDetailFactoryBean">
        <!-- 指定任务类 -->
        <property name="jobClass" value="com.demo.job.MyJob"></property>
        <!-- 当Job在没有可以使⽤的trigger的情况下 不删除 -->
        <property name="durability" value="true"></property>
    </bean>

    <!-- 注意 spring quartz整合 ⼀个trigger只可以绑定⼀个JobDetail ⼀个jobDetail可以被多个Trigger所使⽤ -->
    <bean id="trigger" class="org.springframework.scheduling.quartz.CronTriggerFactoryBean">
        <!-- 绑定JobDetail -->
        <property name="jobDetail" ref="jobDetail"></property>
        <property name="cronExpression" value="0-30 * * * * ?"></property>
    </bean>
    <bean id="trigger1" class="org.springframework.scheduling.quartz.CronTriggerFactoryBean">
        <!--绑定JobDetail-->
        <property name="jobDetail" ref="jobDetail"></property>
        <property name="cronExpression" value="30-59 * * * * ?"></property>
    </bean>

    <!--注册trigger,进行任务管理-->
    <bean id="scheduler" class="org.springframework.scheduling.quartz.SchedulerFactoryBean">
        <!-- 指定集群的配置文件 -->
        <property name="configLocation" value="classpath:quartz-cluster.properties"></property>
        <property name="triggers">
            <list>
                <ref bean="trigger"></ref>
                <ref bean="trigger1"></ref>
            </list>
        </property>
    </bean>
</beans>
3. 启动spring⼯⼚并测试
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值