Quartz任务调度

Quartz概念

Quartz是openSymphony开源组织在Job scheduling领域的开源项目,它可以与J2EE与J2SE应用程序相结合,也可以单独使用。

Quartz是开源且具有丰富特性的“任务调度库”,能够集成于任何的Java应用,小到独立的应用,大到电子商业系统。Quartz能够创建亦简单亦复杂的调度,以执行上百、千,甚至上万的任务。任务job被定义为标准的Java组件,能够执行任何你想要实现的功能。

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

Quartz运行环境

Quartz可以运行嵌入在另一个独立式应用程序
Quartz可以在应用程序服务器(或servlet容器)内被实例化,并且参与事务
Quartz可以作为一个独立的程序运行(其自己的Java虚拟机内),可以通过RMI使用
Quartz可以被实例化,作为独立的项目集群(负载均衡和故障转移功能),用于作业的执行

Quartz设计模式

Builder模式
Factory模式
组件模式
链式模式

Quartz的核心概念

1、任务job
Job就是你想要实现的任务类,每一个Job必须实现org.quartz.job接口,且只需要实现接口定义的execute()方法。

2、触发器Trigger
Trigger为你执行任务的触发器。不如说每天定时3点发送一份统计邮件,Trigger将会设置3点进行执行该任务。
Trigger主要包含两种: SimpleTrigger 和 CronTrigger两种。

3、调度器Scheduler
Scheduler为任务的调度器,它会将任务job及触发器Trigger整合起来,负责基于Trigger设定的时间来执行Job。

Quartz的体系结构

在这里插入图片描述

Quartz的几个常用API

以下是Quartz编程API几个重要接口,也是Quartz的重要组件

1、Scheduler
用于与调度程序交互的主程序接口
Scheduler调度程序通过任务执行计划表,只有安排进执行计划的任务Job(通过scheduler.scheduleJob方法安排进执行计划),当它预先定义的执行时间到了的时候(任务触发trigger),该任务才会执行。

2、Job
我们预先定义的希望在未来时间能够被调度程序执行的任务类,我们可以自定义

3、JobDetail
使用JobDetail来定义定时任务的实例,JobDetail实例通过JobBuilder类创建的。

4、JobDataMap
可以包含不限量的(序列化的)数据对象,在job实例执行的时候,可以使用其中的数据;JobDataMap是Java Map接口的一个实现,额外增加了一些便于存取基本类型的数据的方法。

5、Trigger触发器
Trigger对象是用来触发执行job的。当调度一个job时,我们实例一个触发器然后调整它的属性来满足job执行的条件。表明任务在什么时候会执行。定义了一个已经被安排的任务将会在什么时候执行的时间条件,比方说每两秒钟执行一次。

6、JobBuilder
用于声明一个任务实例,也可以定义关于该任务的详情,比如任务名、组名等,这个声明的实例将会作为一个实际执行的任务。

7、TriggerBuilder
触发器创建器,用于创建触发器trigger实例

8、JobListener、TriggerListener、SchedulerListener监听器,用于对组件的监听

Quartz的使用

入门案例

新建maven项目,导入依赖

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

创建HelloJob任务类

package com.affection.quartz.job;

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

import java.text.SimpleDateFormat;
import java.util.Date;

/**
 * @author 邢道荣
 * @date 2022/12/9 14:25
 */
public class HelloJob implements Job {
    @Override
    public void execute(JobExecutionContext context) throws JobExecutionException {
        // 输出当前时间
        Date date = new Date();
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        String dateString = sdf.format(date);
        // 工作内容

        System.out.println("数据库正在进行备份,备份时间是:" + dateString);
    }
}

然后创建任务调度类HelloSchedulerDemo

package com.affection.quartz.job;

import org.quartz.JobBuilder;
import org.quartz.JobDetail;
import org.quartz.Scheduler;
import org.quartz.SimpleScheduleBuilder;
import org.quartz.Trigger;
import org.quartz.TriggerBuilder;
import org.quartz.impl.StdSchedulerFactory;

/**
 * @author 邢道荣
 * @date 2022/12/9 14:30
 */
public class HelloSchedulerDemo {
    public static void main(String[] args) throws Exception {
        // 1、调度器(Scheduler)
        Scheduler scheduler = StdSchedulerFactory.getDefaultScheduler();

        // 2、任务实例(JobDetail)
        JobDetail jobDetail = JobBuilder.newJob(HelloJob.class)
                .withIdentity("job1", "group1") //参数1: 任务的名称(唯一实例); 参数二: 任务组的名称
                .build();

        // 3、触发器(Trigger)
        Trigger trigger = TriggerBuilder.newTrigger()
                .withIdentity("trigger1", "group1") // 参数1:触发器的名称(唯一实例); 参数2:触发器组的名称
                .startNow() // 马上启动触发器
                .withSchedule(SimpleScheduleBuilder.repeatSecondlyForever(1))
                .build();

        // 让调度器关联任务和触发器,保证按照触发器定义的条件执行任务
        scheduler.scheduleJob(jobDetail, trigger);
        scheduler.start();
    }
}

Job与JobDetail介绍

Job:工作任务调度的接口,任务类需要实现该接口。该接口中定义了execute方法,类似于JDK提供的TimeTask类的run方法。在里面编写任务执行的业务逻辑。

Job实例在Quartz中的生命周期:每次调度器执行Job时,它在调用execute方法前会创建一个新的job实例,当调用完成后,关联的Job对象实例会被释放,释放的实例会被垃圾回收机制回收。

JobDetail: JobDetail为Job实例提供了许多设置属性,以及JobDataMap成员变量属性,它用来存储特定Job实例的状态信息,调度器需要借助JobDetail对象来添加Job实例。

JobDetail重要属性:name、group、jobClass、JobDataMap

JobExecutionContext介绍

当Scheduler调用一个Job,就会将JobExecutionContext传递给Job的execute()方法;

Job能通过JobExecutionContext对象访问到Quartz运行时候的环境以及Job本身的明细数据。

public class HelloJob implements Job {


    @Override
    public void execute(JobExecutionContext context) throws JobExecutionException {
        // 输出当前时间
        Date date = new Date();
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        String dateString = sdf.format(date);
        // 工作内容
        System.out.println("数据库正在进行备份,备份时间是:" + dateString);

        JobKey jobKey = context.getJobDetail().getKey();
        System.out.println("工作任务名称:" + jobKey.getName() + "; 工作任务的组:" + jobKey.getGroup());
        System.out.println("任务类的名称:" + context.getJobDetail().getJobClass().getSimpleName());
    }
}

JobDataMap介绍

(1)、使用Map获取。
在进行任务调度时,JobDataMap存储在JobExecutionContext中,非常方便获取。
JobDataMap可以用来装载任何可序列化的数据对象,当job实例对象被执行时这些参数对象会传递给它。
JobDataMap实现了JDK的Map接口,并且添加了非常方便的方法用来存取基本数据类型。

public class HelloJob implements Job {


    @Override
    public void execute(JobExecutionContext context) throws JobExecutionException {
        // 输出当前时间
        Date date = new Date();
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        String dateString = sdf.format(date);
        // 工作内容
        System.out.println("数据库正在进行备份,备份时间是:" + dateString);

        JobKey jobKey = context.getJobDetail().getKey();
        System.out.println("工作任务名称:" + jobKey.getName() + "; 工作任务的组:" + jobKey.getGroup());
        System.out.println("任务类的名称:" + context.getJobDetail().getJobClass().getName());
        System.out.println("任务类的名称:" + context.getJobDetail().getJobClass().getSimpleName());

        // 从JobDetail对象中获取JobDataMap的数据
        JobDataMap jobDataMap = context.getJobDetail().getJobDataMap();
        String message = jobDataMap.getString("message");
        System.out.println("任务数据的参数值:" + message);

        // 获取Trigger对象中获取jobDataMap的数据
        JobDataMap jobDataMapTrigger = context.getTrigger().getJobDataMap();
        String messageTriagger = jobDataMapTrigger.getString("message");
        System.out.println("触发器数据的参数值:" + messageTriagger);

        // 获取Trigger的内容
        TriggerKey triggerKey = context.getTrigger().getKey();
        System.out.println("触发器名称:" + triggerKey.getName() + " ;  触发器组: " + triggerKey.getGroup());
    }
}

public class HelloSchedulerDemo {
    public static void main(String[] args) throws Exception {
        // 1、调度器(Scheduler)
        Scheduler scheduler = StdSchedulerFactory.getDefaultScheduler();

        // 2、任务实例(JobDetail)
        JobDetail jobDetail = JobBuilder.newJob(HelloJob.class)
                .withIdentity("job1", "group1") //参数1: 任务的名称(唯一实例); 参数二: 任务组的名称
                .usingJobData("message", "打印日志")  // 传递参数,名称message
                .build();


        // 3、触发器(Trigger)
        Trigger trigger = TriggerBuilder.newTrigger()
                .withIdentity("trigger1", "group1") // 参数1:触发器的名称(唯一实例); 参数2:触发器组的名称
                .startNow() // 马上启动触发器
                .withSchedule(SimpleScheduleBuilder.repeatSecondlyForever(1))
                .usingJobData("message", "simple触发器") // 传递参数,名称 message
                .build();

        // 让调度器关联任务和触发器,保证按照触发器定义的条件执行任务
        scheduler.scheduleJob(jobDetail, trigger);
        scheduler.start();
    }
}

(2)、Job实现类中添加setter方法对应JobDataMap的键值,Quartz框架默认的JobFactory实现类在初始化Job实例对象时会自动地调用这些setter方法。

public class HelloJob implements Job {

    private String message;

    public void setMessage(String message) {
        this.message = message;
    }

    @Override
    public void execute(JobExecutionContext context) throws JobExecutionException {
        System.out.println(message);
    }
}

如果遇到同名的key,Trigger中的usingJobData会覆盖JobDetail中的usingJobData。

有状态的Job与无状态的Job

@PersistJobDataAfterExecution注解的使用

有状态的Job可以理解为多次调用Job期间可以持有一些状态信息,这些状态信息存储在JobDataMap中,而默认的无状态job每次调用时都会创建一个新的JobDataMap。

@PersistJobDataAfterExecution // 多次调用Job的时候,会对Job进行持久化,即保存一个数据的信息
public class HelloJob implements Job {
    private Integer count;

    public void setCount(Integer count) {
        this.count = count;
    }

    @Override
    public void execute(JobExecutionContext context) throws JobExecutionException {
        // 累加count
        ++count;
        // 将count存放到JobDataMap中
        context.getJobDetail().getJobDataMap().put("count", count);
        System.out.println("count的数量:" + count);
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

零陵上将军_xdr

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值