面试官问:订单的定时提醒支付功能是怎么实现的?我的回答让我拿到了offer!

在项目中常常会想要这样的功能:在客户把商品加入到购物车后,如果30分钟没支付该订单,那么该订单失效,或者在这个时候提醒客户进行支付,这些需求的实现都来自于定时任务调度框架.

今天来学一个简单的任务调度框架Quartz

简介

Quartz:

是一个定时任务调度框架.比如你遇到这样的问题:

  • 想在30分钟后,查看订单是否支付,未支付则取消订单
  • 想在每月29号,信用卡自动还款
  • 想定时在某个时间,去做某件事(任务)

​ Quartz是要做定时任务的调度,设置好触发时间规则,以及相应任务(Job)即可.

Quartz使用

导入依赖

        <!-- Quartz任务调度  -->
        <dependency>
            <groupId>org.quartz-scheduler</groupId>
            <artifactId>quartz</artifactId>
            <version>2.2.1</version>
        </dependency>

定制一个Job(任务)

实现接口Job

package per.leiyu;

import org.quartz.*;

/**
 * @author 雷雨
 * @date 2020/6/27 21:05
 */

/**
 * 定义了一个Job任务
 */
public class MyJob01 implements Job {
    @Override
    public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException {
        System.out.println("你好,我是定时任务");


        //可以通过JobExecutionContext来获取任务的标识(name)和组别(group)
        JobDetail jobDetail = jobExecutionContext.getJobDetail();
        JobKey key = jobDetail.getKey();
        System.out.println(key.getName());//任务标识
        System.out.println(key.getGroup());//任务组别
    }
}

Quartz API

package per.leiyu;

/**
 * @author 雷雨
 * @date 2020/6/27 21:06
 */

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

import java.util.GregorianCalendar;

/**
 * Quartz  API
 */
public class HelloQuartz {
    public static void main(String[] args) throws SchedulerException {
        //1.定义一个调度器  Scheduler
        Scheduler scheduler = StdSchedulerFactory.getDefaultScheduler();

        //2.定义一个触发器
        //触发器中描述任务Job的触发规则
        SimpleTrigger trigger = TriggerBuilder.newTrigger().withIdentity("trigger1", "group1")
                .startNow()
                .withSchedule(SimpleScheduleBuilder.simpleSchedule().withIntervalInSeconds(2).withRepeatCount(10))
                .endAt(new GregorianCalendar(2020, 5, 27, 21, 25, 30).getTime())
                .build();

        //3,JobDetail
        //注意jbo的名字和组别和触发器的名称和组别是隔离的,那么就可以同名
        JobDetail jobDetail = JobBuilder.newJob(MyJob01.class).withIdentity("job1", "group1").build();

        //4.将JobDetail和触发器添加到调度器中
        scheduler.scheduleJob(jobDetail,trigger);

        //5.启动  调度器开始工作
        scheduler.start();

    }
}

测试结果

定时任务结果,为了方便观察在输出中加了时间戳
image-20200627212813536

配置

可以添加Quartz的配置文件,设置Quartz的默认启动配置

#名为:quartz.properties ,放置在classpath下,如果没有此配置则按默认配置启动
# 指定调度器名称,非实现类
org.quarz.scheduler.instanceName = DefaultQuartzScheduler
#指定线程池实现类
org.quartz.threadPool.class=org.quartz.simpl.SimpleThreadPool
#线程池线程数量
org.quartz.threadPool.threadCount=10
#优先级,默认5
org.quartz,threadPool.threadPriority= 5
#非持久化job
org.quartz.jobStore.class = org.quartz.simpl.RAMJobStore

核心类说明

  • Scheduler:调度器.所有的调度都是由它控制,是Quartz的大脑,所有任务和调度都由它管理
  • Job:任务,想定时执行的事情(定义业务逻辑)
  • JobDetail:基于Job,进一步包装.其中关联一个Job,并为Job指定更为详细的属性,比如标识等
  • Trigger:触发器.可以指定给某个任务,指定任务的触发机制

Trigger

SimpleTrigger

以一定的时间间隔(单位是毫秒)执行的任务

  • 指定起始和截止时间(时间段)
  • 指定时间间隔,执行次数
        SimpleTrigger trigger = TriggerBuilder.newTrigger().withIdentity("trigger1", "group1")
            .startNow()
            .withSchedule(SimpleScheduleBuilder.simpleSchedule().withIntervalInSeconds(2)//每两秒执行一次
            .withRepeatCount(10))//执行次数不超过10次
            .endAt(new GregorianCalendar(2020, 5, 27, 21, 30, 30).getTime())
            .build();
        SimpleTrigger trigger = TriggerBuilder.newTrigger().withIdentity("trigger1", "group1")
            .startNow()
            .withSchedule(SimpleScheduleBuilder.simpleSchedule().withIntervalInSeconds(2)//每两秒执行一次
            .repeatForever())//不限制执行次数,由起始截止时间和间隔决定执行次数
            .endAt(new GregorianCalendar(2020, 5, 27, 21, 30, 30).getTime())
            .build();
  • 注意在SimpleTrigger中指定月份是0代表的是1月,1代表的是2月

CronTrigger

适合于更复杂的任务,它支持类型于Linux Cron的语法(很强大)

  • 执行Cron表达式即可

示例:

        CronTrigger trigger1 = TriggerBuilder.newTrigger()
                .withIdentity("trigger1","group1")
                .withSchedule(CronScheduleBuilder.cronSchedule("0 0/2 10-12 * * ?"))
                .build();

Cron表达式组成

表达式组成"秒 分 时 日 月 星期几 [年]",其中年是可选参数,一般不指定

  • 注意日 ,月可以决定星期,因此如果日,月执行明确的话,星期用 ?表示
位置 时间域 允许值 特殊值
1 0-59 ,-*/
2 分钟 0-59 ,-*/
3 小时 0-23 ,-*/
4 日期 1-31 ,-*?/LW
5 月份 1-12 ,-*/
6 星期 1-7 ,-*?/LW
7 年份(可选) ,-*/
  • 在CronTrigger中表示月份是1代表的是1月,2代表的是2月
  • 用数字1是的是星期天,数字2表示的是星期1,星期也可以使用英文表示

Cron表达式符号

表达式中可使用的符号的含义

符号 语义
星号(*) 可用在所有字段中,表示对应时间域的每一个时刻,例如在分钟字段中,表示的是"每分钟"
问号(?) 该字符只在日期和星期字段中使用,它通常指定为"不确定值"
减号(-) 表示一个范围,如在小时字段中使用"10-12",则表示从10点到12点,即10,11,12
逗号(,) 表示一个列表值,如在星期字段中使用"MON,WEB,FRI",则表示星期一,星期二,星期三
斜杆(/) x/y表示一个等步长序列,x为起始值,y为增量步长值.如在分钟字段中使用0/15,则表示的是0,15,30,45,分钟
井号(#) 该字符只用在星期字段中,"4#2"表示的是第二个星期3,"5#4"表示的是第4个星期四
L 该字符只能出现在日期和星期字段中,代表的是"Last"的意思,但它在两个字段中含义不同
如果L用在星期字段中,则表示星期6,等同于7
L出现在星期字段中,而且在前面有一个数值x,则表示"这个月最后一个周x",例如:6L代表这个月最后一个周五
L在日期字段中,表示这个月份的最后一天,如一月的31号
W 该字符只能出现在日期字段里,是对前导日期的修饰,表示离该日期最近的工作日
例如15W表示离该月15号最近的工作日,如果该月15号是星期六,则匹配14号星期五,如果15号是星期日,则匹配16号星期一;如果15号是星期二,那结果就是15号星期二;但必须注意关联的匹配日期不能跨月
LW组合 在日期字段可以组合使用LW,它的意思是当月的最后一个工作日

我是雷雨,一个普本科的学生,主要专注于Java后端和大数据开发

如果这篇文章有帮助到你,希望你给我一个大大的赞
如果有什么问题,希望你能留言和我一起研究,学习靠自觉,分享靠自愿

转载注明出处
https://blog.csdn.net/qq_40742223

猜你喜欢

转载自blog.csdn.net/qq_40742223/article/details/106999570