本文介绍: 1、分布式调用之 quartz 基本原理

任务调度需求分析

任务调度的实现方式有很多,如果要实现我们的调度需求,我们对这个工具有什么样的基本要求呢?

基本需求

1.可以定义触发的规则,比如基于时刻、时间间隔、表达式。
2.可以定义需要执行的任务。比如执行一个脚本或者一段代码。任务和规则是分开的。
3.集中管理配置,持久配置。不用把规则写在代码里面,可以看到所有的任务配置,方便维护。重启之后任务可以再次调度——配置文件或者配置中心。
4.支持任务的串行执行,例如执行 A 任务后再执行 B 任务再执行 C 任务。
5.支持多个任务并发执行,互不干扰(例如 ScheduledThreadPoolExecutor)。
6.有自己的调度器,可以启动、中断、停止任务。
7.容易集成到 Spring。

任务调度工具对比

在这里插入图片描述

Timer

单线程执行

import java.util.Timer;
import java.util.TimerTask;

public class TestTimerTask extends TimerTask {
    /**
     * 此计时器任务要执行的操作。
     */
    public void run() {
        Date executeTime = new Date(this.scheduledExecutionTime());
        String dateStr = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date());
        System.out.println("任务执行了:" + dateStr);
    }
}



public class TestTimer {
    public static void main(String[] args) {
        Timer timer = new Timer();
        TimerTask task = new TestTimerTask();
        timer.schedule(task, 5000L, 1000L);
    }
}

Quartz

基本介绍

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

  • Quatz 是一个特性丰富的,开源的任务调度库,它几乎可以嵌入所有的 Java 程序,从很小的独立应用程序到大型商业系统。Quartz 可以用来创建成百上千的简单的或者复杂的任务,这些任务可以用来执行任何程序可以做的事情。

  • Quartz 拥有很多企业级的特性,包括支持 JTA 事务和集群。

  • Quartz 是一个老牌的任务调度系统,98 年构思,01 年发布到 sourceforge。现在更新比较慢,因为已经非常成熟了。https://github.com/quartz-scheduler/quartz

  • Quartz 的目的就是让任务调度更加简单,开发人员只需要关注业务即可。他是用 Java 语言编写的(也有.NET 的版本)。Java 代码能做的任何事情,Quartz 都可以调度。
    特点:

  • 精确到毫秒级别的调度

  • 可以独立运行,也可以集成到容器中

  • 支持事务(JobStoreCMT )

  • 支持集群

  • 支持持久化

体系结构总结

在这里插入图片描述

JobDetail

我们创建一个实现 Job 接口的类,使用 JobBuilder 包装成 JobDetail,它可以携带KV 的数据。

Trigger

定义任务的触发规律,Trigger,使用 TriggerBuilder 来构建。
JobDetail 跟 Trigger 是 1:N 的关系。
思考:为什么要解耦?
Trigger 接口在 Quartz 有 4 个继承的子接口:
在这里插入图片描述

MutableTrigger 和 CoreTrigger 最终也是用到以上四个类的实现类。

在这里插入图片描述

SimpleTrigger

SimpleTrigger 可以定义固定时刻或者固定时间间隔的调度规则(精确到毫秒)。
例如:每天 9 点钟运行;每隔 30 分钟运行一次。

CalendarIntervalTrigger

CalendarIntervalTrigger 可以定义更多时间单位的调度需求,精确到秒。
好处是不需要去计算时间间隔,比如 1 个小时等于多少毫秒。
例如每年、每个月、每周、每天、每小时、每分钟、每秒。
每年的月数和每个月的天数不是固定的,这种情况也适用。

DailyTimeIntervalTrigger

每天的某个时间段内,以一定的时间间隔执行任务。
例如:每天早上 9 点到晚上 9 点,每隔半个小时执行一次,并且只在周一到周六执
行。

CronTrigger

CronTirgger 可以定义基于 Cron 表达式的调度规则,是最常用的触发器类型
在这里插入图片描述

上面我们定义的都是在什么时间执行,但是我们有一些在什么时间不执行的需求,
比如:理财周末和法定假日购买不计息;证券公司周末和法定假日休市。
是不是要把日期写在数据库中,然后读取基于当前时间判断呢?
基于 Calendar 的排除规则
如果要在触发器的基础上,排除一些时间区间不执行任务,就要用到 Quartz 的
Calendar 类(注意不是 JDK 的 Calendar)。可以按年、月、周、日、特定日期、Cron表达式排除
在这里插入图片描述

调用 Trigger 的 modifiedByCalendar()添加到触发器中,并且调用调度器的
addCalendar()方法注册排除规则
在这里插入图片描述

public class CalendarDemo {
    public static void main(String[] args) throws Exception {
        SchedulerFactory sf = new StdSchedulerFactory();
        Scheduler scheduler = sf.getScheduler();
        scheduler.start();

        // 定义日历
        AnnualCalendar holidays = new AnnualCalendar();

        // 排除日
        Calendar gupaoDay = (Calendar) new GregorianCalendar(2019, 8, 8);
        holidays.setDayExcluded(gupaoDay, true);
        // 排除中秋节
        Calendar midAutumn = new GregorianCalendar(2019, 9, 13);
        holidays.setDayExcluded(midAutumn, true);
        // 排除圣诞节
        Calendar christmas = new GregorianCalendar(2019, 12, 25);
        holidays.setDayExcluded(christmas, true);

        // 调度器添加日历
        scheduler.addCalendar("holidays", holidays, false, false);

        JobDetail jobDetail = JobBuilder.newJob(MyJob1.class)
                .withIdentity("job1", "group1")
                .usingJobData("gupao","测试 2673")
                .build();

        Trigger trigger = TriggerBuilder.newTrigger()
                .withIdentity("trigger1", "group1")
                .startNow()
                .modifiedByCalendar("holidays")
                .withSchedule(SimpleScheduleBuilder.simpleSchedule()
                        .withIntervalInSeconds(2)
                        .repeatForever())
                .build();

        Date firstRunTime = scheduler.scheduleJob(jobDetail, trigger);
        System.out.println(jobDetail.getKey() + " 第一次触发: " + firstRunTime);
    }
}

Scheduler

调度器,是 Quartz 的指挥官,由 StdSchedulerFactory 产生。它是单例的。
并且是 Quartz 中最重要的 API,默认是实现类是 StdScheduler,里面包含了一个
QuartzScheduler。QuartzScheduler 里面又包含了一个 QuartzSchedulerThread。
在这里插入图片描述

Scheduler 中的方法主要分为三大类:
1)操作调度器本身,例如调度器的启动 start()、调度器的关闭 shutdown()。
2)操作 Trigger,例如 pauseTriggers()、resumeTrigger()。
3)操作 Job,例如 scheduleJob()、unscheduleJob()、rescheduleJob()
这些方法非常重要,可以实现任务的动态调度

Listener

我们有这么一种需求,在每个任务运行结束之后发送通知给运维管理员。那是不是
要在每个任务的最后添加一行代码呢?这种方式对原来的代码造成了入侵,不利于维护。
如果代码不是写在任务代码的最后一行,怎么知道任务执行完了呢?或者说,怎么监测
到任务的生命周期呢?

  • 观察者模式:定义对象间一种一对多的依赖关系,使得每当一个对象改变状态,则
    所有依赖它的对象都会得到通知并自动更新。

  • Quartz 中提供了三种 Listener,监听 Scheduler 的,监听 Trigger 的,监听 Job 的。
    只需要创建类实现相应的接口,并在 Scheduler 上注册 Listener,便可实现对核心
    对象的监听。

JobListener

在这里插入图片描述

TriggerListener

在这里插入图片描述

SchedulerListener
方法比较多,省略

JobStore

问题:最多可以运行多少个任务(磁盘、内存、线程数)

Jobstore 用来存储任务和触发器相关的信息,例如所有任务的名称、数量、状态等
等。Quartz 中有两种存储任务的方式,一种在在内存,一种是在数据库。

RAMJobStore

Quartz 默认的 JobStore 是 RAMJobstore,也就是把任务和触发器信息运行的信息存储在内存中,用到了 HashMap、TreeSet、HashSet 等等数据结构。
如果程序崩溃或重启,所有存储在内存中的数据都会丢失。所以我们需要把这些数据持久化到磁盘。

JDBCJobStore

JDBCJobStore 可以通过 JDBC 接口,将任务运行数据保存在数据库中
在这里插入图片描述

JDBC 的实现方式有两种,JobStoreSupport 类的两个子类:
JobStoreTX:在独立的程序中使用,自己管理事务,不参与外部事务。
JobStoreCMT:(Container Managed Transactions (CMT),如果需要容器管理事务时,使用它。
使用 JDBCJobSotre 时,需要配置数据库信息:

org.quartz.jobStore.class:org.quartz.impl.jdbcjobstore.JobStoreTX
org.quartz.jobStore.driverDelegateClass:org.quartz.impl.jdbcjobstore.StdJDBCDelegate
# 使用 quartz.properties,不使用默认配置
org.quartz.jobStore.useProperties:true
#数据库中 quartz 表的表名前缀
org.quartz.jobStore.tablePrefix:QRTZ_
org.quartz.jobStore.dataSource:myDS
#配置数据源
org.quartz.dataSource.myDS.driver:com.mysql.jdbc.Driver
org.quartz.dataSource.myDS.URL:jdbc:mysql://localhost:3306/gupao?useUnicode=true&characterEncoding=utf8
org.quartz.dataSource.myDS.user:root
org.quartz.dataSource.myDS.password:123456
org.quartz.dataSource.myDS.validationQuery=select 0 from dual

问题来了?需要建什么表?表里面有什么字段?字段类型和长度是什么?

在官网的 Downloads 链接中,提供了 11 张表的建表语句:quartz-2.2.3-distributionquartz-2.2.3docsdbTables
2.3 的版本在这个路径下:srcorgquartzimpljdbcjobstore

在这里插入图片描述

原文地址:https://blog.csdn.net/qq_25385555/article/details/135893374

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。

如若转载,请注明出处:http://www.7code.cn/show_64087.html

如若内容造成侵权/违法违规/事实不符,请联系代码007邮箱:suwngjj01@126.com进行投诉反馈,一经查实,立即删除!

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注