引入Quartz

关于任务调度

  关于任务调度,Java.util.Timer是最简单的一种实现任务调度的方法,简单的使用如下:

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

public class TimerTest {
    public static void main(String[] args) {
        Timer timer = new Timer();
        long delay = 1000;    //延时多少秒开始执行
        long period =1000;    //执行周期
        timer.schedule(new MyTask(),delay,period);
    }
}

class MyTask extends TimerTask{

    @Override
    public void run() {
        System.out.println("Hello World");
    }
}

  使用 Timer 实现任务调度的核心类是 Timer 和 TimerTask。其中 Timer 负责设定 TimerTask 的起始与间隔执行时间。使用者只需要创建一个 TimerTask 的继承类,实现自己的 run 方法,然后将其丢给 Timer 去执行即可。

   Timer 的设计核心是一个 TaskList 和一个 TaskThread。Timer 将接收到的任务丢到自己的 TaskList 中,TaskList 按照 Task 的最初执行时间进行排序。TimerThread 在创建 Timer 时会启动成为一个守护线程。这个线程会轮询所有任务,找到一个最近要执行的任务,然后休眠,当到达最近要执行任务的开始时间点,TimerThread 被唤醒并执行该任务。之后 TimerThread 更新最近一个要执行的任务,继续休眠。

引入Quartz

    Quartz学习笔记:基础知识

  Quartz 是一个完全由 Java 编写开源作业调度框架,为在 Java 应用程序中进行作业调度提供了简单却强大的机制。

Quartz的核心概念

  我们需要明白 Quartz 的几个核心概念,这样理解起 Quartz 的原理就会变得简单了。

    Quartz学习笔记:基础知识

  1. Job 表示一个工作,要执行的具体内容。类似于TimerTask类。需要实现方法 void execute(JobExecutionContext context) 
  2. JobDetail 表示一个具体的可执行的调度程序,Job 是这个可执行程调度程序所要执行的内容,另外 JobDetail 还包含了这个任务调度的方案和策略。 
  3. Trigger 代表一个调度参数的配置,什么时候去调。 
  4. Scheduler 代表一个调度容器。类似于Timer类。一个调度容器中可以注册多个 JobDetail 和 Trigger。当 Trigger 与 JobDetail 组合,就可以被 Scheduler 容器调用。

  

快速开始

Scheduler(调度器)

  Scheduler的生命期,从SchedulerFactory创建它时开始,到Scheduler调用shutdown()方法时结束;Scheduler被创建后,可以增加、删除和列举Job和Trigger,以及执行其它与调度相关的操作(如暂停Trigger)。但是,Scheduler只有在调用start()方法后,才会真正地触发trigger(即执行job)。

  //1、通过工程创建调度器
  SchedulerFactory schedFact = new org.quartz.impl.StdSchedulerFactory();
  Scheduler sched = schedFact.getScheduler();
  //2、启动调度器
  sched.start();

Job、JobDetail(任务及任务细节)

  使用者只需要创建一个 Job 的子类,实现 execute 方法。JobDetail 负责封装 Job 以及 Job 的属性,并将其提供给 Scheduler 作为参数。每次 Scheduler 执行任务时,首先会创建一个 Job 的实例,然后再调用 execute 方法执行。Quartz 没有为 Job 设计带参数的构造函数,因此需要通过额外的 JobDataMap 来存储 Job 的属性。JobDataMap 可以存储任意数量的 Key,Value 对。

//[!]存储普通类型
jobDetail.getJobDataMap().put("myDescription", "my job description"); 
jobDetail.getJobDataMap().put("myValue", 1998); 
//[!]存储对象
ArrayList<String> list = new ArrayList<String>(); 
list.add("item1"); 
jobDetail.getJobDataMap().put("myArray", list);

  JobDataMap中的数据获取可以通过下面这种方式:

public class JobDataMapTest implements Job {
 
    @Override
    public void execute(JobExecutionContext context) throws JobExecutionException {
        //从context中获取instName,groupName以及dataMap
        String instName = context.getJobDetail().getName();
        String groupName = context.getJobDetail().getGroup();
        JobDataMap dataMap = context.getJobDetail().getJobDataMap();
        //从dataMap中获取myDescription,myValue以及myArray
        String myDescription = dataMap.getString("myDescription");
        int myValue = dataMap.getInt("myValue");
        ArrayList<String> myArray = (ArrayListlt;Strin>) dataMap.get("myArray");
        System.out.println("
                Instance =" + instName + ", group = " + groupName
                + ", description = " + myDescription + ", value =" + myValue
                + ", array item0 = " + myArray.get(0));
 
    }
}

Trigger(触发器)

  Trigger 的作用是设置调度策略。Quartz 设计了多种类型的 Trigger,其中最常用的是 SimpleTrigger 和 CronTrigger。

  • SimpleTrigger 适用于在某一特定的时间执行一次,或者在某一特定的时间以某一特定时间间隔执行多次。上述功能决定了 SimpleTrigger 的参数包括 start-time, end-time, repeat count, 以及 repeat interval。
  • CronTrigger 的用途更广,相比基于特定时间间隔进行调度安排的 SimpleTrigger,CronTrigger 主要适用于基于日历的调度安排。例如:每星期二的 16:38:10 执行,每月一号执行,以及更复杂的调度安排等。

  CronTrigger的使用如下:

CronTrigger cronTrigger = new CronTrigger("myTrigger", "myGroup"); 
try { 
    cronTrigger.setCronExpression("0 0/30 20-13 ? * MON-WED,SAT"); 
} catch (Exception e) { 
    e.printStackTrace(); 
}

Listener(监听器)

  Quartz 还提供了 listener 的功能。主要包含三种 listener:

  • JobListener
  • TriggerListener
  • SchedulerListener

  当系统发生故障,相关人员需要被通知时,Listener 便能发挥它的作用。最常见的情况是,当任务被执行时,系统发生故障,Listener 监听到错误,立即发送邮件给管理员

  关于监听器的问题,我们会在之后认真讨论。

JobStores

  Quartz 的另一显著优点在于持久化,即将任务调度的相关数据保存下来。这样,当系统重启后,任务被调度的状态依然存在于系统中,不会丢失。默认情况下,Quartz 采用的是 org.quartz.simpl.RAMJobStore,在这种情况下,数据仅能保存在内存中,系统重启后会全部丢失。若想持久化数据,需要采用 org.quartz.simpl.JDBCJobStoreTX

  第一步:创建数据库及表。

  第二部:配置数据源。

# Configure ThreadPool 
org.quartz.threadPool.class = org.quartz.simpl.SimpleThreadPool 
org.quartz.threadPool.threadCount =  5 
org.quartz.threadPool.threadPriority = 4 
 
# Configure Datasources 
org.quartz.jobStore.class = org.quartz.impl.jdbcjobstore.JobStoreTX 
org.quartz.jobStore.driverDelegateClass = org.quartz.impl.jdbcjobstore.StdJDBCDelegate 
org.quartz.jobStore.dataSource = db2DS 
org.quartz.jobStore.tablePrefix = QRTZ_ 
 
org.quartz.dataSource.db2DS.driver = com.ibm.db2.jcc.DB2Driver 
org.quartz.dataSource.db2DS.URL = jdbc:db2://localhost:50001/sched 
org.quartz.dataSource.db2DS.user = quartz 
org.quartz.dataSource.db2DS.password = passw0rd 
org.quartz.dataSource.db2DS.maxConnections = 5

  使用时只需要将 quatz.properties 放在 classpath 下面,不用更改一行代码,再次运行之前的任务调度实例,trigger、job 等信息便会被记录在数据库中。

一个调度任务的创建

  最后我们再来回顾一下,我们一个调度系统的增加一个任务的全流程:

  //1、定义JobDetail,注意需要实现定义Job,实现execute方法即可
  JobDetail job = newJob(HelloJob.class)
      .withIdentity("job1", "group1")
      .build();

  //2、定义触发器,即任务的执行策略
  Trigger trigger = newTrigger()
      .withIdentity("trigger1", "group1")
      .startNow()
            .withSchedule(simpleSchedule()
              .withIntervalInSeconds(40)
              .repeatForever())            
      .build();

  //3、告诉Quartz去调度使用了trigger触发器的job
  scheduler.scheduleJob(job, trigger);

 参考链接

相关文章:

  • 2021-10-16
  • 2021-10-16
  • 2019-03-04
  • 2022-02-14
  • 2021-12-23
  • 2022-01-02
  • 2021-06-17
  • 2021-06-16
猜你喜欢
  • 2021-12-04
  • 2021-05-28
  • 2021-11-10
  • 2021-05-22
  • 2021-05-30
  • 2021-10-01
  • 2020-06-14
相关资源
相似解决方案