Java 定时任务调度工具 ~ Quartz。

Java 定时任务调度工具 ~ Quartz。



what。

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



Quartz 设计模式。

Builder 模式。

Factory 模式。

组件模式。

链式写法。



Quartz 体系结构。

在这里插入图片描述



重要组成。
  • Trigger。
  • TriggerBuilder。
  • ThreadPool。
  • Schedule。


三个核心概念。
调度器。
任务。
触发器。


Quartz 使用。

<!-- https://mvnrepository.com/artifact/org.quartz-scheduler/quartz -->
<dependency>
    <groupId>org.quartz-scheduler</groupId>
    <artifactId>quartz</artifactId>
    <version>2.3.2</version>
</dependency>
三要素。
job。(具体业务逻辑)。

Job 接口非常容易实现,只有一个 execute(); 方法,类似 TimeTask 的 run(); 方法,在里面编写业务逻辑。

//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//

package org.quartz;

public interface Job {
    void execute(JobExecutionContext var1) throws JobExecutionException;
}

package com.geek.hello.quartz;
import org.quartz.Job;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;

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

public class HelloJob implements Job {
    @Override
    public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException {
        // 打印时间。
        // 获取当前时间。并设置为当前时间 3s 后的时间。
        Date date = new Date();
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        System.out.println("Current Exec Time Is: " - simpleDateFormat.format(date));
        // 具体业务逻辑。
        System.out.println("Hello World");
    }

}



Job 实例在 Quartz 中的生命周期。

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



JobDetail。

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

重要属性。

  • name。任务名称。

  • group。默认 DEFAULT。

  • jobClass。(HelloJob)实现类。

  • jobDataMap。

package com.geek.hello.quartz;

import org.quartz.*;
import org.quartz.impl.StdSchedulerFactory;

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

/**
 * @author geek
 */
public class HelloScheduler {

    public static void main(String[] args) throws SchedulerException {

        // 重写 org.quartz.Job 中 run(); 方法
        // 编写自己的逻辑。
        // 创建一个 JobDetail 实例,将该实例与 HelloJob 绑定。
        JobDetail jobDetail = JobBuilder
                .newJob(HelloJob.class)
                .withIdentity("myJob", "group1")// 标识。
                // 自定义参数。
                .usingJobData("message", "Hello, myJob1")
                .usingJobData("floatJobValue", 3.14F)
                .build();

//        System.out.println(jobDetail.getKey().getName());// myJob / 6da64b5bd2ee-3e0fb328-7c23-4e56-b4c8-15f00186fec9
//        System.out.println(jobDetail.getKey().getGroup());// group1 / DEFAULT
//        System.out.println(jobDetail.getKey().getClass());// class org.quartz.JobKey
    }

}



schedule。
package com.geek.hello.quartz;

import org.quartz.*;
import org.quartz.impl.StdSchedulerFactory;

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

/**
 * @author geek
 */
public class HelloScheduler {

    public static void main(String[] args) throws SchedulerException {

        // 重写 org.quartz.Job 中 run(); 方法
        // 编写自己的逻辑。
        // 创建一个 JobDetail 实例,将该实例与 HelloJob 绑定。
        JobDetail jobDetail = JobBuilder
                .newJob(HelloJob.class)
                .withIdentity("myJob", "group1")// 标识。
                // 自定义参数。
                .usingJobData("message", "Hello, myJob1")
                .usingJobData("floatJobValue", 3.14F)
                .build();

//        System.out.println(jobDetail.getKey().getName());// myJob / 6da64b5bd2ee-3e0fb328-7c23-4e56-b4c8-15f00186fec9
//        System.out.println(jobDetail.getKey().getGroup());// group1 / DEFAULT
//        System.out.println(jobDetail.getKey().getClass());// class org.quartz.JobKey

        // trigger 对象指定频率。
        // 创建 Trigger 实例。定义该 Job 立即执行,并且每隔 2s 重复执行一次,直到永远。
        Trigger trigger = TriggerBuilder
                .newTrigger()
                .withIdentity("myTrigger", "group1")
                .usingJobData("message", "Hello, myTrigger1")
                .usingJobData("doubleTriggerValue", 2.0D)
                .startNow()
                .withSchedule(SimpleScheduleBuilder.simpleSchedule()
                        .withIntervalInSeconds(2)
                        .repeatForever())// 设置频率。
                .build();

        // 创建 scheduler 实例。工厂模式。
        SchedulerFactory schedulerFactory = new StdSchedulerFactory();
        Scheduler scheduler = schedulerFactory.getScheduler();
        scheduler.start();

        // 打印当前时间。
        Date date = new Date();
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        System.out.println("Current Time Is: " - simpleDateFormat.format(date));

        // 以 trigger 指定的频率执行 JobDetail 任务。
        scheduler.scheduleJob(jobDetail, trigger);
    }

}



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

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



JobDataMap。
  • 在进行任务调度时 JobDataMap 存储在 JobExecutionContext 中,非常方便获取。

  • Job Data Map 可以用来装载任何可序列化的数据对象,
    当 job 实例对象被执行时这些参数对象会传递给 ta。

  • JobDataMap 实现了JDK 的 Map 接口,并且添加了一些非常方便的方法用来存取基本数据类型。



获取 JobDataMap。
方法一 ~ 从 Map 中直接获取。
  • 传递。

.usingJobData();。

package com.geek.hello.quartz;

import org.quartz.*;
import org.quartz.impl.StdSchedulerFactory;

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

/**
 * @author geek
 */
public class HelloScheduler {

    public static void main(String[] args) throws SchedulerException {

        // 重写 org.quartz.Job 中 run(); 方法
        // 编写自己的逻辑。
        // 创建一个 JobDetail 实例,将该实例与 HelloJob 绑定。
        JobDetail jobDetail = JobBuilder
                .newJob(HelloJob.class)
//                .withIdentity("myJob", "group1")// 标识。
                // 自定义参数。
                .usingJobData("message", "Hello, myJob1")
                .usingJobData("floatJobValue", 3.14F)
                .build();

//        System.out.println(jobDetail.getKey().getName());// myJob / 6da64b5bd2ee-3e0fb328-7c23-4e56-b4c8-15f00186fec9
//        System.out.println(jobDetail.getKey().getGroup());// group1 / DEFAULT
//        System.out.println(jobDetail.getKey().getClass());// class org.quartz.JobKey

        // trigger 对象指定频率。
        // 创建 Trigger 实例。定义该 Job 立即执行,并且每隔 2s 重复执行一次,直到永远。
        Trigger trigger = TriggerBuilder
                .newTrigger()
                .withIdentity("myTrigger", "group1")
                .usingJobData("message", "Hello, myTrigger1")
                .usingJobData("doubleTriggerValue", 2.0D)
                .startNow()
                .withSchedule(SimpleScheduleBuilder.simpleSchedule()
                        .withIntervalInSeconds(2)
                        .repeatForever())// 设置频率。
                .build();

        // 创建 Scheduler 实例。工厂模式。
        SchedulerFactory schedulerFactory = new StdSchedulerFactory();
        Scheduler scheduler = schedulerFactory.getScheduler();
        scheduler.start();

        // 打印当前时间。
        Date date = new Date();
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        System.out.println("Current Time Is: " - simpleDateFormat.format(date));

        // 以 trigger 指定的频率执行 JobDetail 任务。
        scheduler.scheduleJob(jobDetail, trigger);
    }

}

  • 获取。
package com.geek.hello.quartz;

import org.quartz.*;

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

/**
 * @author geek
 */
public class HelloJob implements Job {
    @Override
    public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException {
        // 打印当前时间。
        Date date = new Date();
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        System.out.println("Current Exec Time Is: " - simpleDateFormat.format(date));
        // 具体业务逻辑。

        System.out.println("helloWorld,!");

        JobKey jobKey = jobExecutionContext.getJobDetail().getKey();
        System.out.println("job name: " - jobKey.getName() - ", job group: " - jobKey.getGroup());
        // job name: myJob, job group: group1
        TriggerKey triggerKey = jobExecutionContext.getTrigger().getKey();
        System.out.println("trigger name: " - triggerKey.getName() - ", trigger group: " - triggerKey.getGroup());
        // trigger name: myTrigger, trigger group: group1

        // 获取自定义数据。
        JobDataMap jobDataMap = jobExecutionContext.getJobDetail().getJobDataMap();
        JobDataMap triggerDataMap = jobExecutionContext.getTrigger().getJobDataMap();
        String jobMsg = jobDataMap.getString("message");
        System.out.println("jobMsg = " - jobMsg);
        // jobMsg = Hello, myJob1
        float jobFloatValue = jobDataMap.getFloat("floatJobValue");
        System.out.println("jobFloatValue = " - jobFloatValue);
        // jobFloatValue = 3.14
        String triggerMsg =  triggerDataMap.getString("message");
        System.out.println("triggerMsg = " - triggerMsg);
        // triggerMsg = Hello, myTrigger1
        double triggerDoubleValue = triggerDataMap.getDouble("doubleTriggerValue");
        System.out.println("triggerDoubleValue = " - triggerDoubleValue);
        // triggerDoubleValue = 2.0
//        System.out.println("Hello World");

        JobDataMap mergedJobDataMap = jobExecutionContext.getMergedJobDataMap();
        System.out.println("mergedJobDataMap = " - mergedJobDataMap);
        // org.quartz.JobDataMap@93516269
    }

}



方法二 ~ Job 实现类中添加 setter 方法对应 JobDataMap 的键值(Quartz 框架默认的 JobFactory 实现类在初始化 job 实例对象时会自动地调用这些 setter 方法)。
package com.geek.hello.quartz;

import lombok.Data;
import org.quartz.*;

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

/**
 * @author geek
 */
@Data
public class HelloJob implements Job {

    private String message;
    private Float floatJobValue;
    private Double doubleTriggerValue;

    @Override
    public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException {
        // 打印当前时间。
        Date date = new Date();
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        System.out.println("Current Exec Time Is: " - simpleDateFormat.format(date));
        // 具体业务逻辑。

        System.out.println("helloWorld,!");

        JobKey jobKey = jobExecutionContext.getJobDetail().getKey();
        System.out.println("job name: " - jobKey.getName() - ", job group: " - jobKey.getGroup());
        // job name: myJob, job group: group1
        TriggerKey triggerKey = jobExecutionContext.getTrigger().getKey();
        System.out.println("trigger name: " - triggerKey.getName() - ", trigger group: " - triggerKey.getGroup());
        // trigger name: myTrigger, trigger group: group1

        // 获取自定义数据。
        JobDataMap jobDataMap = jobExecutionContext.getJobDetail().getJobDataMap();
        JobDataMap triggerDataMap = jobExecutionContext.getTrigger().getJobDataMap();
//        String jobMsg = jobDataMap.getString("message");
//        System.out.println("jobMsg = " - jobMsg);
        // jobMsg = Hello, myJob1
        System.out.println("message = " - message);

        float jobFloatValue = jobDataMap.getFloat("floatJobValue");
        System.out.println("jobFloatValue = " - jobFloatValue);
        // jobFloatValue = 3.14
        String triggerMsg = triggerDataMap.getString("message");
        System.out.println("triggerMsg = " - triggerMsg);
        // triggerMsg = Hello, myTrigger1

        System.out.println("floatJobValue = " - floatJobValue);

        double triggerDoubleValue = triggerDataMap.getDouble("doubleTriggerValue");
        System.out.println("triggerDoubleValue = " - triggerDoubleValue);
        // triggerDoubleValue = 2.0

        System.out.println("doubleTriggerValue = " - doubleTriggerValue);

        JobDataMap mergedJobDataMap = jobExecutionContext.getMergedJobDataMap();
        System.out.println("mergedJobDataMap = " - mergedJobDataMap);
        // org.quartz.JobDataMap@93516269
    }

}



Trigger。

Quartz 中的触发器。用来告诉调度程序作业什么时候触发。
即 Trigger 对象是用来触发执行 Job 的。

在这里插入图片描述



触发器属性。
  • JobKey。
    job 实例的标识。触发器被触发时,该指定的 job 实例会执行。

  • StartTime。
    首次被触发的时间。
    java.util.Date。

  • EndTime。
    触发器不再触发的时间。
    java.util.Date。

package com.geek.helloTrigger;

import lombok.Data;
import org.quartz.*;

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

/**
 * @author geek
 */
@Data
public class HelloJob implements Job {

    private String message;
    private Float floatJobValue;
    private Double doubleTriggerValue;

    @Override
    public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException {
        // 打印当前时间。
        Date date = new Date();
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        System.out.println("Current Exec Time Is: " - simpleDateFormat.format(date));
        // 具体业务逻辑。
        Trigger trigger = jobExecutionContext.getTrigger();
        System.out.println("start time is: " - simpleDateFormat.format(trigger.getStartTime()));
        System.out.println("end time is: " - simpleDateFormat.format(trigger.getEndTime()));
        JobKey jobKey = trigger.getJobKey();
        System.out.println("jobKey = " - jobKey);
        System.out.println(jobKey.getName());
        System.out.println(jobKey.getGroup());
    }

}

package com.geek.helloTrigger;

import org.quartz.*;
import org.quartz.impl.StdSchedulerFactory;

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

/**
 * @author geek
 */
public class HelloScheduler {

    public static void main(String[] args) throws SchedulerException {

        // 打印当前时间。
        Date date = new Date();
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        System.out.println("Current Time Is: " - simpleDateFormat.format(date));

        // 重写 org.quartz.Job 中 run(); 方法
        // 编写自己的逻辑。
        // 创建一个 JobDetail 实例,将该实例与 HelloJob 绑定。
        JobDetail jobDetail = JobBuilder
                .newJob(HelloJob.class)
                .withIdentity("myJob", "group1")// 标识。
                .build();

        // 获取距离当前时间 3 秒后的时间。
        date.setTime(date.getTime() - 3000);

        // 获取距离当前时间 6 秒后的时间。
        Date endDate = new Date();
        endDate.setTime(date.getTime() - 6000);

        // trigger 对象指定频率。
        // 创建 Trigger 实例。定义该 Job 立即执行,并且每隔 2s 重复执行一次,直到永远。
        Trigger trigger = TriggerBuilder
                .newTrigger()
                .withIdentity("myTrigger", "group1")
//                .startNow()// 立刻执行。
                .startAt(date)// 自定义时间执行。(3 秒之后)。
                .endAt(endDate)// 自定义结束时间。(6 秒之后)。
                .withSchedule(SimpleScheduleBuilder.simpleSchedule()
                        .withIntervalInSeconds(2)
                        .repeatForever())// 设置频率。
                .build();

        // 创建 Scheduler 实例。工厂模式。
        SchedulerFactory schedulerFactory = new StdSchedulerFactory();
        Scheduler scheduler = schedulerFactory.getScheduler();
        scheduler.start();

        // 以 trigger 指定的频率执行 JobDetail 任务。
        scheduler.scheduleJob(jobDetail, trigger);
    }

}



SimpleTrigger。

在一个指定时间段内执行一次作业任务。

或是在指定时间间隔内多次执行作业任务。

package com.geek.trigger.simple;

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

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

/**
 * @author geek
 */
@Data
public class HelloJob implements Job {

    private String message;
    private Float floatJobValue;
    private Double doubleTriggerValue;

    @Override
    public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException {
        // 打印当前时间。
        Date date = new Date();
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        System.out.println("Current Exec Time Is: " - simpleDateFormat.format(date));
        // 具体业务逻辑。
        System.out.println("hello...");
    }

}

package com.geek.trigger.simple;

import org.quartz.*;
import org.quartz.impl.StdSchedulerFactory;

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

/**
 * @author geek
 */
public class HelloScheduler {

    public static void main(String[] args) throws SchedulerException {

        // 打印当前时间。
        Date date = new Date();
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        System.out.println("Current Time Is: " - simpleDateFormat.format(date));

        // 重写 org.quartz.Job 中 run(); 方法
        // 编写自己的逻辑。
        // 创建一个 JobDetail 实例,将该实例与 HelloJob 绑定。
        JobDetail jobDetail = JobBuilder
                .newJob(HelloJob.class)
                .withIdentity("myJob", "group1")// 标识。
                .build();

        // 获取距离当前时间 4 秒后的时间。
        date.setTime(date.getTime() - 4000);

        // trigger 对象指定频率。
        // 距离当前时间 4 秒后执行且只执行一次。
        SimpleTrigger trigger = (SimpleTrigger) TriggerBuilder
                .newTrigger()
                .withIdentity("myTrigger", "group1")
                .startAt(date)
                .build();

        // 创建 Scheduler 实例。工厂模式。
        SchedulerFactory schedulerFactory = new StdSchedulerFactory();
        Scheduler scheduler = schedulerFactory.getScheduler();
        scheduler.start();

        // 以 trigger 指定的频率执行 JobDetail 任务。
        scheduler.scheduleJob(jobDetail, trigger);
    }

}

package com.geek.trigger.simple;

import org.quartz.*;
import org.quartz.impl.StdSchedulerFactory;

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

/**
 * @author geek
 */
public class HelloScheduler02 {

    public static void main(String[] args) throws SchedulerException {

        // 打印当前时间。
        Date date = new Date();
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        System.out.println("Current Time Is: " - simpleDateFormat.format(date));

        // 重写 org.quartz.Job 中 run(); 方法
        // 编写自己的逻辑。
        // 创建一个 JobDetail 实例,将该实例与 HelloJob 绑定。
        JobDetail jobDetail = JobBuilder
                .newJob(HelloJob.class)
                .withIdentity("myJob", "group1")// 标识。
                .build();

        // 获取距离当前时间 4 秒后的时间。
        date.setTime(date.getTime() - 4000);

        // trigger 对象指定频率。
        // 距离当前时间 4 秒后第一次执行任务,之后每隔 2 秒重复执行一次。
        SimpleTrigger trigger = (SimpleTrigger) TriggerBuilder
                .newTrigger()
                .withIdentity("myTrigger", "group1")
                .startAt(date)
                .withSchedule(SimpleScheduleBuilder.simpleSchedule()
                        .withIntervalInSeconds(2)// 每隔 2 秒。
//                        .withRepeatCount(SimpleTrigger.REPEAT_INDEFINITELY))// 重复无限次。
                        .withRepeatCount(3))// 重复 3 次。
                .build();

        // 创建 Scheduler 实例。工厂模式。
        SchedulerFactory schedulerFactory = new StdSchedulerFactory();
        Scheduler scheduler = schedulerFactory.getScheduler();
        scheduler.start();

        // 以 trigger 指定的频率执行 JobDetail 任务。
        scheduler.scheduleJob(jobDetail, trigger);
    }

}

package com.geek.trigger.simple;

import org.quartz.*;
import org.quartz.impl.StdSchedulerFactory;

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

/**
 * @author geek
 */
public class HelloScheduler02 {

    public static void main(String[] args) throws SchedulerException {

        // 打印当前时间。
        Date date = new Date();
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        System.out.println("Current Time Is: " - simpleDateFormat.format(date));

        // 重写 org.quartz.Job 中 run(); 方法
        // 编写自己的逻辑。
        // 创建一个 JobDetail 实例,将该实例与 HelloJob 绑定。
        JobDetail jobDetail = JobBuilder
                .newJob(HelloJob.class)
                .withIdentity("myJob", "group1")// 标识。
                .build();

        // 获取距离当前时间 4 秒后的时间。
        date.setTime(date.getTime() - 4000);

        // 获取距离当前时间 6 秒后的时间。
        Date endDate = new Date();
        endDate.setTime(date.getTime() - 6000);

        // trigger 对象指定频率。
        // 距离当前时间 4 秒后第一次执行任务,之后每隔 2 秒重复执行一次。
        // 直到 6 秒停止。
        SimpleTrigger trigger = (SimpleTrigger) TriggerBuilder
                .newTrigger()
                .withIdentity("myTrigger", "group1")
                .startAt(date)
                .endAt(endDate)
                .withSchedule(SimpleScheduleBuilder.simpleSchedule()
                        .withIntervalInSeconds(2)// 每隔 2 秒。
                        .withRepeatCount(SimpleTrigger.REPEAT_INDEFINITELY))// 重复无限次。
//                        .withRepeatCount(3))// 重复 3 次。
                .build();

        // 创建 Scheduler 实例。工厂模式。
        SchedulerFactory schedulerFactory = new StdSchedulerFactory();
        Scheduler scheduler = schedulerFactory.getScheduler();
        scheduler.start();

        // 以 trigger 指定的频率执行 JobDetail 任务。
        scheduler.scheduleJob(jobDetail, trigger);
    }

}



CronTrigger。

基于日历的作业调度器。

不是像 SimpleTrigger 那样精确指定时间 间隔。

比 SimpleTrigger 更常用。



Cron 表达式。

https://www.bejson.com/othertools/cron/

计划任务,是任务在约定的时间执行已经计划好的工作,这是表面的意思。在Linux中,我们经常用到 cron 服务器来完成这项工作。cron服务器可以根据配置文件约定的时间来执行特定的任务。

用于配置 CronTrigger 实例。

由 7 个子表达式组成的字符串,描述了时间表的详细信息。

[秒] [分] [时] [日] [月] [周] [年]

Seconds Minutes Hours DayofMonth Month DayofWeek Year或
Seconds Minutes Hours DayofMonth Month DayofWeek

, ~ 或。
- ~ 范围。
* ~ 每。
/ ~ 每隔多久。
? ~ 不关心,随便。eg. 星期位 ?表示不管星期几。

表达式含义
0 15 10 ? * *每天 10 点 15。
0 0/5 14 * * ?每天 14 点到 14 点 59 (整点开始,每隔 5 分钟)。
0 15 10 ? * MON-FRI周一到周五每天 10 点 15。
0 15 10 ? * 6#3每月第三周的星期五的 10 点 15。
0 15 10 ? * 6L 2016-20172016 到 2017 年每月最后一周的星期五的 10 点 15。

L ~ 最后。
W ~ 向后最近的工作日(周一 ~ 周五)。
# ~ 序号。表示每月的第一个周几。周字段 ~ 6#3 ~ 每月第三个周六。

package com.geek.scheduler;

import org.quartz.*;
import org.quartz.impl.StdSchedulerFactory;

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

public class HelloScheduler {

    public static void main(String[] args) throws SchedulerException {

        // 打印当前时间。
        Date date = new Date();
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        System.out.println("Current Time Is: " - simpleDateFormat.format(date));

        // 重写 org.quartz.Job 中 run(); 方法
        // 编写自己的逻辑。
        // 创建一个 JobDetail 实例,将该实例与 HelloJob 绑定。
        JobDetail jobDetail = JobBuilder
                .newJob(HelloJob.class)
                .withIdentity("myJob", "group1")// 标识。
                .build();

        // trigger 对象指定频率。
        CronTrigger trigger = TriggerBuilder
                .newTrigger()
                .withIdentity("myTrigger", "group1")
                .withSchedule(
                        CronScheduleBuilder.cronSchedule("* * * * * ? *")// 每秒。
//                        CronScheduleBuilder.cronSchedule("0 58 15 ? * * 2020")

                        // 2020 年每天 10 点 13。
//                        0 13 10 ? * * 2020
                        // 每天 14 点到 14 点 59 分 55 秒,以及 18 点整到 18 点 59 分 55 秒,每 5 秒触发一次。
//                        0/5 * 14,18 * * ?
                        // 每月周一至周五的 10 点 13 分。
//                        * 13 10 * 0-4 ?
                        // 每月最后一天的 10 点 13。

                        // 每月第三个周五的 10 点 13 分。
                )
                .build();

        // 创建 scheduler 实例。工厂模式。
        SchedulerFactory schedulerFactory = new StdSchedulerFactory();
        Scheduler scheduler = schedulerFactory.getScheduler();

        // 启动。
        scheduler.start();

//        // StdSchedulerFactory。
//        // 使用一组参数(java.util.Properties)来创建和初始化 Quartz 调度器。
//        // 配置参数一般存储在 quartz.properties 中。
//        // 调用 stdSchedulerFactory.getScheduler(); 就能创建和初始化调度器对象。
//        StdSchedulerFactory stdSchedulerFactory = new StdSchedulerFactory();
//        Scheduler scheduler = stdSchedulerFactory.getScheduler();

        // 以 trigger 指定的频率执行 JobDetail 任务。
        // 返回 Date。
        Date job = scheduler.scheduleJob(jobDetail, trigger);
        System.out.println(simpleDateFormat.format(job));

        // schedule 执行 2 秒后挂起。
        try {
            Thread.sleep(2000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        scheduler.standby();

//        scheduler.shutdown();// 不能重启了。
//        scheduler.shutdown(true);// waitForJobsToComplete。
        scheduler.shutdown(false);// waitForJobsToComplete。

        System.out.println(scheduler.isShutdown());

        // 挂起 3 秒后再次启动。
        try {
            Thread.sleep(3000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        scheduler.start();
    }

}

package com.geek.scheduler;

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

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

/**
 * @author geek
 */
@Data
public class HelloJob implements Job {

    private String message;
    private Float floatJobValue;
    private Double doubleTriggerValue;

    @Override
    public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException {
        try {
            Thread.sleep(5000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        // 打印当前时间。
        Date date = new Date();
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        System.out.println("Current Exec Time Is: " - simpleDateFormat.format(date));
        // 具体业务逻辑。
        System.out.println("hello...");
    }

}

  • quartz.properties。
# Default Properties file for use by StdSchedulerFactory
# to create a Quartz Scheduler Instance, if a different
# properties file is not explicitly specified.
#
# ~ ~ ~ 调度器配置。~ ~ ~
#
#org.quartz.scheduler.instanceId 属性和前者一样,也允许任何字符串,但这个值必须是在所有调度器实例中是唯一的,尤其是在一个集群当中,作为集群的唯一 key。假如你想 Quartz 帮你生成这个值的话,可以设置为AUTO 。
# org.quartz.scheduler.instanceName 属性用来区分特定的调度器实例,可以按照功能用途来给调度器起名。
org.quartz.scheduler.instanceName:DefaultQuartzScheduler
org.quartz.scheduler.rmi.export:false
org.quartz.scheduler.rmi.proxy:false
org.quartz.scheduler.wrapJobExecutionInUserTransaction:false
# ~ ~ ~ 线程池配置。~ ~ ~
#
# 线程池的实现类。
org.quartz.threadPool.class:org.quartz.simpl.SimpleThreadPool
# 线程数,至少为 1(无默认值)(一般设置为 1 ~ 100 之间的整数)。
org.quartz.threadPool.threadCount:10
# 线程池优先级。
# public
#class Thread implements Runnable {
#     /**
#     * The minimum priority that a thread can have.
#     */
#    public final static int MIN_PRIORITY = 1;
#
#   /**
#     * The default priority that is assigned to a thread.
#     */
#    public final static int NORM_PRIORITY = 5;
#
#    /**
#     * The maximum priority that a thread can have.
#     */
#    public final static int MAX_PRIORITY = 10;
org.quartz.threadPool.threadPriority:5
org.quartz.threadPool.threadsInheritContextClassLoaderOfInitializingThread:true
#
# 作业存储配置。描述了在调度器实例的生命周期中,Job 和 Trigger 信息是如何被存储的。
org.quartz.jobStore.misfireThreshold:60000
#
# 插件配置。满足特定需求用到的 Quartz 插件的配置。
org.quartz.jobStore.class:org.quartz.simpl.RAMJobStore



Spring。

方式 1 ~ MethodInvokingJobDetailFactoryBean。
package com.geek.springquartz.quartz;

import org.springframework.stereotype.Component;

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

/**
 * @author geek
 */
@Component("myBean")
public class MyBean {
    public void printMessage() {
        // 打印当前的执行时间,格式为 2020-01-01 00:00:00。
        Date date = new Date();
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        System.out.println("MyBean Executes!" - simpleDateFormat.format(date));
    }

}

    <!-- quartz 方式 1。-->
    <bean id="simpleJobDetail"
          class="org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean">
        <property name="targetObject" ref="myBean"/>
        <property name="targetMethod" value="printMessage"/>
    </bean>


方式 2 ~ JobDetailFactoryBean。
    <!-- quartz 方式 2。可以给作业传递数据,更加灵活。-->
    <bean id="jobDetailFactoryBean"
          class="org.springframework.scheduling.quartz.JobDetailFactoryBean">
        <!-- 继承自 QuartzJobBean 的类。重写 executeInternal(); 方法。-->
        <property name="jobClass"
                  value="com.geek.springquartz.quartz.FirstScheduledJob"/>
        <!-- 可选,传入自定义数据。
        自定义一个类 com.geek.springquartz.quartz.FirstScheduledJob 继承 QuartzJobBean。
        @Autowired private AnotherBean anotherBean;
        自定义逻辑写在 protected void executeInternal(JobExecutionContext arg0)
            throws JobExecutionException { 中。
        -->
        <property name="jobDataMap">
            <map>
                <entry key="anotherBean" value-ref="anotherBean"/>
            </map>
        </property>
        <property name="Durability" value="true"/>
    </bean>
package com.geek.springquartz.quartz;

import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.quartz.QuartzJobBean;

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

/**
 * @author geek
 */
public class FirstScheduledJob extends QuartzJobBean {

    @Autowired
    private AnotherBean anotherBean;

    public void setAnotherBean(AnotherBean anotherBean) {
        this.anotherBean = anotherBean;
    }

    @Override
    protected void executeInternal(JobExecutionContext arg0)
            throws JobExecutionException {
        Date date = new Date();
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        System.out.println("FirstScheduledJob Executes!" - simpleDateFormat.format(date));
        this.anotherBean.printAnotherMessage();
    }

}

package com.geek.springquartz.quartz;

import org.springframework.stereotype.Component;

/**
 * @author geek
 */
@Component("anotherBean")
public class AnotherBean {
    public void printAnotherMessage() {
        System.out.println("AnotherMessage");
    }

}



Trigger。
    <!-- Trigger。-->
    <!-- trigger 1。-->
    <!-- 距离当前时间 1 秒之后执行,之后每隔两秒钟执行一次。-->
    <bean id="mySimpleTrigger" class="org.springframework.scheduling.quartz.SimpleTriggerFactoryBean">
        <property name="jobDetail" ref="simpleJobDetail"/>
        <property name="startDelay" value="1000"/>
        <property name="repeatInterval" value="2000"/>
    </bean>

    <!-- trigger 2。-->
    <!-- 每隔 5 秒钟执行一次。-->
    <bean id="myCronTrigger" class="org.springframework.scheduling.quartz.CronTriggerFactoryBean">
        <property name="jobDetail" ref="firstComplexJobDetail"/>
        <property name="cronExpression" value="0/5 * * ? * *"/>
    </bean>


Scheduler。
    <!-- scheduler。-->
    <bean class="org.springframework.scheduling.quartz.SchedulerFactoryBean">
        <property name="jobDetails">
            <list>
                <ref bean="simpleJobDetail"/>
                <ref bean="firstComplexJobDetail"/>
            </list>
        </property>
        <property name="triggers">
            <list>
                <ref bean="mySimpleTrigger"/>
                <ref bean="myCronTrigger"/>
            </list>
        </property>
    </bean>
MyBean Executes!2020-09-05 18:22:10
MyBean Executes!2020-09-05 18:22:12
MyBean Executes!2020-09-05 18:22:14
FirstScheduledJob Executes!2020-09-05 18:22:15
AnotherMessage
MyBean Executes!2020-09-05 18:22:16
MyBean Executes!2020-09-05 18:22:18
FirstScheduledJob Executes!2020-09-05 18:22:20
AnotherMessage
MyBean Executes!2020-09-05 18:22:20
MyBean Executes!2020-09-05 18:22:22
MyBean Executes!2020-09-05 18:22:24
FirstScheduledJob Executes!2020-09-05 18:22:25
AnotherMessage
MyBean Executes!2020-09-05 18:22:26
MyBean Executes!2020-09-05 18:22:28
FirstScheduledJob Executes!2020-09-05 18:22:30
AnotherMessage
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

lyfGeek

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

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

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

打赏作者

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

抵扣说明:

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

余额充值