zoukankan      html  css  js  c++  java
  • Java定时任务调度框架Quartz入门详解案例

    一、什么是Quartz

    Quartz是OpenSymphony开源组织在Job scheduling领域又一个开源项目,完全由Java开发,可以用来执行定时任务,类似于java.util.Timer。但是相较于Timer, Quartz增加了很多功能:

    • 持久性作业 - 就是保持调度定时的状态;
    • 作业管理 - 对调度作业进行有效的管理;

    拿火车票购票来说,当你下单后,后台就会插入一条待支付的task(job),一般是30分钟,超过30min后就会执行这个job,去判断你是否支付,未支付就会取消此次订单;当你支付完成之后,后台拿到支付回调后就会再插入一条待消费的task(job),Job触发日期为火车票上的出发日期,超过这个时间就会执行这个job,判断是否使用等。

    二、Quartz核心概念

    1.任务/作业(Task/Job)

    位于org.quartz.Job的接口,是quartz中的核心任务接口,要实现自定义的定时任务(就是我们要执行的业务动作/作业)只需要实现此接口。

    这里写图片描述

    2.触发器(Trigger)

    位于org.quartz.Trigger,触发器用来告诉调度程序作业什么时候触发,也就是我们要设置任务触发的条件。quartz提供了5种触发器类型,但两个最常用的SimpleTrigger和CronTrigger。

    五种类型的Trigger(触发器):
    SimpleTrigger,CronTirgger,DateIntervalTrigger,NthIncludedDayTrigger和Calendar。

    这里写图片描述

    3.调度器(Schedule)

    来自org.quartz.Schedule是Quartz Scheduler的主要接口,代表一个独立运行容器。调度程序维护JobDetails和触发器的注册表。 一旦注册,调度器负责执行作业,当他们的相关联的触发器触发时(当他们的预定时间到达时)。不难看出功能就是将任务job与触发器Trigger作业结合起来。

    img

    4.任务执行时上下文(JobExecutionContext)

    位于org.quartz.JobExecutionContext的类,是任务在执行时quartz注入的对象,用于保存任务的详细信息(比如触发器,调度器,工作详情,任务入参等),我们可以通过此对象得到运行时的任务数据,也可以接受动态参数。

    主要有以下方法:

    image-20210104144243980

    5.任务详情(JobDetail)

    位于org.quartz.JobDetail,用来绑定job,为job提供一些属性:

    • name:唯一标识
    • group:分组标识
    • jobClass:具体任务
    • jobDataMap:任务入参

    为什么设计成JobDetail + Job,不直接使用Job?

    JobDetail定义的是任务数据,而真正的执行逻辑是在Job中。
    这是因为任务是有可能并发执行,如果Scheduler直接使用Job,就会存在对同一个Job实例并发访问的问题。而JobDetail & Job 方式,Sheduler每次执行,都会根据JobDetail创建一个新的Job实例,这样就可以规避并发访问的问题。

    三、案例demo实现

    1.定义自定义任务,继承job接口

    public class MyJob implements Job {
    
        private final Logger log = LoggerFactory.getLogger(MyJob.class);
    
        @Override
        public void execute(JobExecutionContext context) throws JobExecutionException {
            log.error("定时任务:发送一次消息,时间={"+ LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"))+
                    "}");
            log.error("请求参数:{name="+context..getJobDetail().getJobDataMap().get("name").toString()+",sign="+context.getJobDetail().getJobDataMap().get("sign").toString()+"}");
        }
    }
    

    2.创建demo

    public class Demo {
    
        public static void main(String[] args) throws SchedulerException {
            //1.初始化调度器工厂
            SchedulerFactory schedulerFactory = new StdSchedulerFactory();
            //2.获取调度器
            Scheduler scheduler = schedulerFactory.getScheduler();
    
            //3.创建任务实例
            JobDetail jobDetail = newJob(MyJob.class)//一个静态builder方法
                    .withDescription("这是我的入门实例Job")//任务备注
                    .withIdentity("demoJob","demoGroup")//标识与分组
                    .usingJobData("name","张三")//传入参数
                    .usingJobData("sign","abcdefg")
                    .build();
            //4.创建任务触发器
            Trigger trigger = TriggerBuilder.newTrigger()
                    .withIdentity("demoJob","demoGroup")
                    /*.withSchedule(SimpleScheduleBuilder.simpleSchedule()//简单任务触发器
                        .withIntervalInSeconds(10)//每10秒执行一次
                        .withRepeatCount(5)//执行5次
                    )*/
                    .withSchedule(CronScheduleBuilder.cronSchedule("*/5 * * * * ?"))//定时触发调度器
                    .startAt(new Date(System.currentTimeMillis()+10))//十秒后开始执行任务
                    .build();
            //5.将任务和触发器注入到quartz中
            scheduler.scheduleJob(jobDetail,trigger);
    
            //6.启动任务
            scheduler.start();
        }
    
    }
    

    3.运行测试,注意运行就会触发一次任务,然后每5秒触发一次

    四、CronExpression表达式详解

    通过使用不难发现任务执行的条件才是我们最关心的,quartz支持Cron表达式来定义触发器规则。

    • “*”字符被用来指定所有的值。如:”“在分钟的字段域里表示“每分钟”。
    • “-”字符被用来指定一个范围。如:“10-12”在小时域意味着“10点、11点、12点”。
    • “,”字符被用来指定另外的值。如:“MON,WED,FRI”在星期域里表示”星期一、星期三、星期五”.
    • “?”字符只在日期域和星期域中使用。它被用来指定“非明确的值”。当你需要通过在这两个域中的一个来指定一些东西的时候,它是有用的。看下面的例子你就会明白。
    • “L”字符指定在月或者星期中的某天(最后一天)。即“Last ”的缩写。但是在星期和月中“L”表示不同的意思,如:在月子段中“L”指月份的最后一天-1月31日,2月28日,如果在星期字段中则简单的表示为“7”或者“SAT”。如果在星期字段中在某个value值得后面,则表示“某月的最后一个星期value”,如“6L”表示某月的最后一个星期五。
    • “W”字符只能用在月份字段中,该字段指定了离指定日期最近的那个星期日。
    • “#”字符只能用在星期字段,该字段指定了第几个星期value在某月中

    结合示例更加清晰:

  • 相关阅读:
    iSCSI又称为IPSAN
    文档类型定义DTD
    HDU 2971 Tower
    HDU 1588 Gauss Fibonacci
    URAL 1005 Stone Pile
    URAL 1003 Parity
    URAL 1002 Phone Numbers
    URAL 1007 Code Words
    HDU 3306 Another kind of Fibonacci
    FZU 1683 纪念SlingShot
  • 原文地址:https://www.cnblogs.com/StarChen20/p/14230049.html
Copyright © 2011-2022 走看看