SpringBoot Quartz 定时任务详解

转载请标明出处:http://blog.csdn.net/zhaoyanjun6/article/details/80657415
本文出自【赵彦军的博客】

Quartz 简介

JavaEE系统中,我们会经常用到定时任务,比如每天凌晨生成前天报表,每一小时生成汇总数据等等。

我们可以使用java.util.Timer结合java.util.TimerTask来完成这项工作,但时调度控制非常不方便,并且我们需要大量的代码。

使用Quartz框架无疑是非常好的选择,并且与Spring可以非常方便的集成,下面介绍它们集成方法和Cron表达式的详细介绍。

Quartz 集成

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

依赖:

<dependency>
      <groupId>org.quartz-scheduler</groupId>
      <artifactId>quartz</artifactId>
      <version>2.2.1</version>
  </dependency>
  <dependency>
      <groupId>org.quartz-scheduler</groupId>
      <artifactId>quartz-jobs</artifactId>
      <version>2.2.1</version>
  </dependency>   

实例1

创建 Job

package com.yiba.didiapi.job;

import org.quartz.*;

import java.util.Date;

public class MyJob implements Job {

    @Override
    public void execute(JobExecutionContext context) throws JobExecutionException {
        System.out.println("任务执行了: ");

        JobDataMap dataMap = context.getMergedJobDataMap();
        String name = dataMap.getString("name");  //获取名字
        Integer age = dataMap.getInt("age");    //获取年龄

        System.out.println("name: " + name + "  age:" + age);

        JobDetail jobDetail = context.getJobDetail();
        String jobName = jobDetail.getKey().getName();
        String jobGroup = jobDetail.getKey().getGroup();

        System.out.println("jobName: " + jobName + "  jobGroup:" + jobGroup);

        Trigger trigger = context.getTrigger();
        String triggerName = trigger.getKey().getName();
        String triggerGroup = trigger.getKey().getGroup();
        Date startTime = trigger.getStartTime();  //获取任务开始时间
        Date endTime = trigger.getEndTime();    //获取任务结束时间

        System.out.println("triggerName: " + triggerName + "  triggerGroup:" + triggerGroup);

    }
}

创建 JobScheduler

package com.yiba.didiapi.job;

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

import java.util.Date;

public class JobScheduler {

    public static void main(String[] args)  {
        JobDetail jobDetail = JobBuilder
                .newJob(MyJob.class)
                .withIdentity("jobName", "jobGroup")  //定义job的名字和组
                .usingJobData("name", "yanjun")  //传参数,key:name value:yanjun
                .usingJobData("age", 18)  //传参数,key:age value:18
                .build();

        //定义开始时间
        Date startDate = new Date();

        //定义结束时间,在开始时间之后10秒
        Date endDate = new Date(startDate.getTime() + 10 * 1000);
        //触发器 
        Trigger trigger = TriggerBuilder.newTrigger()
                .withIdentity("triggerName", "triggerGroup")
                .startNow()  //现在开始执行
                .startAt(startDate)  //在指定的时间开始执行
                .endAt(endDate)      //在指定的时间结束执行
                .withSchedule(SimpleScheduleBuilder
                        .simpleSchedule()
                        .repeatForever()  //永远执行下去
                        .withRepeatCount(10)  //执行10.withIntervalInSeconds(1)  //一秒钟执行一次
                )
                .build();


        try {
            SchedulerFactory factory = new StdSchedulerFactory();
            Scheduler scheduler = factory.getScheduler();
            scheduler.scheduleJob(jobDetail,trigger);
            scheduler.start(); //开始执行
        } catch (SchedulerException e) {
            e.printStackTrace();
        }
  }
}

CronTrigger

Quartz有两大触发器,除了上面使用的SimpleTrigger外,就是CronTriggerCronTrigger能够提供复杂的触发器表达式的支持。CronTrigger是基于Unix Cron守护进程,它是一个调度程序,支持简单而强大的触发器语法。

使用CronTrigger主要的是要掌握Cron表达式。Cron表达式包含6个必要组件和一个可选组件,如下表所示。

Cron 表达式是由 7个子表达式组成的字符串,描述了时间表的详细信息。
格式:[秒] [分] [小时] [日] [月] [周] [年]

位置 含义 允许的特殊字符
1 秒(0~59) , - * /
2 分(0~59) , - * /
3 小时(0~23) , - * /
4 日期(1~31) , - * / ? L W C
5 月(JAN~DEC或1~12) , - * /
6 星期(SUN~SAT或1~7) , - * / ? L C #
7 年(可选,1970~2099),若为空,表示全部时间范围 , - * /

特殊字符的含义,见下表

特 殊 字 符 说 明
* 通配符,任意值
? 无特定值。通常和其他指定的值一起使用,表示必须显示该值但不能检查
- 范围。e.g.小时部分10-12表示10:00,11:00, 12:00
, 列分隔符。可以让你指定一系列的值。e.g.在星期域中指定MON、TUE和WED
/ 增量。表示一个值的增量,e.g.分钟域中0/1表示从0开始,每次增加1min
L 表示Last。它在日期和星期域中表示有所不同。在日期域中,表示这个月的最后一天,而在星期域中,它永远是7(星期六)。当你希望使用星期中某一天时,L字符非常有用。e.g.星期域中6L表示每一个月的最后一个星期五
W 在本月内离当天最近的工作日触发,所谓的最近工作日,即当天到工作日的前后最短距离,如果当天即为工作日,则距离是0;所谓本月内指的是不能跨月取到最近工作日,即使前/后月份的最后一天/第一天确实满足最近工作日。e.g. LW表示本月的最后一个工作日触发,W强烈依赖月份。
# 表示该月的第几个星期,e.g. 1#2表示每一个月的第一个星期一
C 日历值。日期值是根据一个给定的日历计算出来的。在日期域中给定一个20C将在20日(日历包括20日)或20日后日历中包含的第一天(不包括20日)激活触发器。例如在一个星期域中使用6C表示日历中星期五(日历包括星期五)或者第一天(日历不包括星期五)

常见的Cron表达式举例

"30 * * * * ?"              //每半分钟触发任务
"30 10 * * * ?"             //每小时的10分30秒触发任务
"30 10 1 * * ?"             //每天1点10分30秒触发任务
"30 10 1 20 * ?"            //每月20号1点10分30秒触发任务
"30 10 1 20 10 ? *"         //每年10月20号1点10分30秒触发任务
"30 10 1 20 10 ? 2011"      //2011年10月20号1点10分30秒触发任务
"30 10 1 ? 10 * 2011"       //2011年10月每天1点10分30秒触发任务
"30 10 1 ? 10 SUN 2011"     //2011年10月每周日1点10分30秒触发任务
"15,30,45 * * * * ?"        //每15秒,30秒,45秒时触发任务
"15-45 * * * * ?"           //15到45秒内,每秒都触发任务
"15/5 * * * * ?"            //每分钟的每15秒开始触发,每隔5秒触发一次
"15-30/5 * * * * ?"         //每分钟的15秒到30秒之间开始触发,每隔5秒触发一次
"0 0/3 * * * ?"             //每小时的第0分0秒开始,每三分钟触发一次
"0 15 10 ? * MON-FRI"       //星期一到星期五的10点15分0秒触发任务
"0 15 10 L * ?"             //每个月最后一天的10点15分0秒触发任务
"0 15 10 LW * ?"            //每个月最后一个工作日的10点15分0秒触发任务
"0 15 10 ? * 5L"            //每个月最后一个星期四的10点15分0秒触发任务
"0 15 10 ? * 5#3"           //每个月第三周的星期四的10点15分0秒触发任务

CronTrigger 实例

package com.yiba.didiapi.job;

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

public class JobScheduler {

    public static void main(String[] args)  {
        JobDetail jobDetail = JobBuilder
                .newJob(MyJob.class)
                .withIdentity("jobName", "jobGroup")  //定义job的名字和组
                .usingJobData("name", "yanjun")  //传参数,key:name value:yanjun
                .usingJobData("age", 18)  //传参数,key:age value:18
                .build();

        String cronExpression = "0/1 * * * * ?"; //每一秒执行一次

        CronTrigger trigger = (CronTrigger) TriggerBuilder.newTrigger()
                .withIdentity("triggerName", "triggerGroup")
                .withSchedule(CronScheduleBuilder
                        .cronSchedule(cronExpression)
                )
                .build();

        try {
            SchedulerFactory factory = new StdSchedulerFactory();
            Scheduler scheduler = factory.getScheduler();
            scheduler.scheduleJob(jobDetail,trigger);
            scheduler.start(); //开始执行
        } catch (SchedulerException e) {
            e.printStackTrace();
        }

    }

}

Scheduler

//创建一个 Scheduler 
SchedulerFactory factory = new StdSchedulerFactory();
Scheduler scheduler = factory.getScheduler();

//给调度器设置 job,trigger
scheduler.scheduleJob(jobDetail,trigger);
scheduler.start(); //开始执行

scheduler.standby(); //调度器挂起,挂起后可以通过 start 重启

//立即关闭调度器,关闭后,不能重启
scheduler.shutdown() ; 

//true:等待所有的job都执行完,然后再关闭scheduler
//false:立即关闭scheduler
scheduler.shutdown(true);  

scheduler.isShutdown();  //是否关闭了
scheduler.isStarted();  //是否启动了
scheduler.isInStandbyMode() ; //是否挂起了

个人微信号:zhaoyanjun125 , 欢迎关注

猜你喜欢

转载自blog.csdn.net/zhaoyanjun6/article/details/80657415