Springboot 集成Quartz实现定时任务

一、JAVA常见的几种定时任务比较

  • Timer:jdk自带的java.util.Timer类,这个类允许你调度一个java.util.TimerTask任务。使用这种方式可以让程序按照某一个频度执行,但不能在指定时间运行,一般很少使用,主要用于非Spring项目简单的任务调度。
  • Spring
    Task:Spring3.0以后自带的Task,可以将它看成一个轻量级的Quartz,使用起来比Quartz简单很多,在Spring应用中,直接使用@Scheduled注解即可,但对于集群项目比较麻烦,需要避免集群环境下任务被多次调用的情况,而且不能动态维护,任务启动以后不能修改、暂停等。
  • Quartz:好用的第三方任务调度工具,可谓是企业级应用系统任务调度工具的老大。可以方便的在集群下使用、可以动态增加、删除、暂停等维护任务,动态定时任务更加灵活。而且,和Spring
    Boot集成非常方便。

二、本博客将用Quartz来实现定时任务
Quartz的简单介绍:
核心概念:调度器、任务和触发器

Job
  • 是一个接口,有一个方法void execute(),可以通过实现该接口来定义需要执行的任务 JobDetail:Quartz
    每次执行job时,都重新创建一个Job实例,会接收一个Job实现类,以便运行的时候通过newInstance()的反射调用机制去实例化
Job.JobDetail
  • 是用来描述Job实现类以及相关静态信息,比如任务在scheduler中的组名等信息
Trigger
  • 描述触发Job执行的时间触发规则实现类SimpleTrigger和CronTrigger
  • 可以通过crom表达式定义出各种复杂的调度方案
Calendar
  • 是一些日历特定时间的集合。一个Trigger可以和多个 calendar关联,比如每周一早上10:00执行任务,法定假日不执行, 则可以通过calendar进行定点排除
Scheduler
  • 代表一个 Quartz的独立运行容器。Trigger和JobDetail可以注册到Scheduler中。Scheduler可以将Trigger绑定到某一JobDetail上,这样当Trigger被触发时,对应的Job就会执行。一个Job可以对应多个Trigger,但一个Trigger只能对应一个Job.

在这里插入图片描述
三、案例实现,代码中有详细注解

  1. 首先创建springboot项目:
    在这里插入图片描述

2.创建一个QuartzConfig类,并添加@Configuration注解:

package com.example.demo;

import org.quartz.*;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class QuartzConfig {

    @Bean
    public JobDetail testQuartz1() {
        return JobBuilder.newJob(QuartzTest1.class) //QuartzTest1是我们的业务类
                .withIdentity("quartzTest1") //给该JobDetail起一个id
                .storeDurably() //即使没有Trigger关联时,也不需要删除该JobDetail
                //每个JobDetail内都有一个Map,包含了关联到这个Job的数据,在Job类中可以通过context获取
                .usingJobData("msg", "Hello Quartz")//关联键值对
                .build();
    }

    @Bean
    public Trigger testQuartzTrigger1() {
        //5秒执行一次
        SimpleScheduleBuilder scheduleBuilder = SimpleScheduleBuilder.simpleSchedule()
                .withIntervalInSeconds(5)
                .repeatForever();
        return TriggerBuilder.newTrigger()
                .forJob(testQuartz1()) //关联上述的JobDetail
                .withIdentity("quartzTest1") //给Trigger起个名字
                .withSchedule(scheduleBuilder)
                .build();
    }

    @Bean
    public JobDetail testQuartz2() {
        return JobBuilder.newJob(QuartzTest2.class)
                .withIdentity("quartzTest2") //给该JobDetail起一个id
                .storeDurably() //即使没有Trigger关联时,也不需要删除该JobDetail
                .build();
    }

    @Bean
    public Trigger testQuartzTrigger2() {
        //cron方式,每隔5秒执行一次
        CronScheduleBuilder cronScheduleBuilder = CronScheduleBuilder.cronSchedule("*/5 * * * * ?");
        return TriggerBuilder.newTrigger()
                .forJob(testQuartz2()) //关联上述的JobDetail
                .withIdentity("quartzTest2") //给Trigger起个名字
                .withSchedule(cronScheduleBuilder)
                .build();
    }

}

3.这里为了展示固定间隔和cron表达式,创建了两个任务

QuartzTest1 :

package com.example.demo;

import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
import org.springframework.scheduling.quartz.QuartzJobBean;
import java.text.SimpleDateFormat;
import java.util.Date;

public class QuartzTest1 extends QuartzJobBean {

    @Override
    protected void executeInternal(JobExecutionContext jobExecutionContext) throws JobExecutionException {
        SimpleDateFormat sdf=new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        System.out.println("TestQuartz01----" + sdf.format(new Date()));
    }

}

QuartzTest2 :

package com.example.demo;

import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
import org.springframework.scheduling.quartz.QuartzJobBean;
import java.text.SimpleDateFormat;
import java.util.Date;

public class QuartzTest2 extends QuartzJobBean {
    @Override
    protected void executeInternal(JobExecutionContext jobExecutionContext) throws JobExecutionException {
        SimpleDateFormat sdf=new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        System.out.println("TestQuartz02----" + sdf.format(new Date()));
    }
}

testTask1使用的固定间隔方式,testTask2使用的是cron表达式方式。

4.测试
在这里插入图片描述
四、cron表达式
注:下面内容主要参考Quartz的文档,对于Spring Task基本都适用。

cron表达式是由7个域组成的字符串,它们描述了任务计划的各个细节,这些域用空格分隔,每个域代表的含义如下:

  • Seconds(秒)
  • Minutes(分)
  • Hours(时)
  • Day-of-Month(日)
  • Month(月)
  • Day-of-Week(星期) Year(可选字段)(年)

示例:0 0 10 ? * WED表示每个星期三的10:00:00

在这里插入图片描述

说明:下面描述中,XX域则表示cron表达式相应的位置,如秒域表示cron中第1个值,日域则表示cron表达式第4个值等等。

  • 月份简称:JAN,FEB,MAR,APR,MAY,JUN,JUL,AUG,SEP,OCT,NOV和DEC。

  • 星期简称:SUN,MON,TUE,WED,THU,FRI和SAT。其中,1表示SUN。

  • ,:用来分割在域上指定的多个值。如:MON,WED,FRI在星期域里表示星期一、星期三、星期五。

  • /:用于指定增量值。如分钟上使用0/15,表示从零开始,每隔15分钟,等价于0,15,30,45。如分钟上使用3/15,表示从第3分钟开始,每隔

  • 15分钟,等价于3,18,33,48,x/y中x表示开始值,y表示步长。

  • :表示匹配该域的任意值。如秒上使用表示每秒触发一次。

  • -:表示指定一个范围,如分钟域上10-13,表示10分、11分、12分、13分。

  • ?:表示不关心的域,可用于日和周两个域上,主要用来解决日和周两个域的冲突。和类似,区别在于关心域,只是域的值可以任意,?则表示对该域不关心,不需要看该域的内容,直接忽略。

  • L:表示最后,是单词last的首字母,可用于日和周两个域上,用在日和周上含义不同:
    日域上表示月份中日期的最后一天,如一月的第31天、非闰年二月的第28天。
    周域上单独使用仅表示7或SAT,即仅表示周六。但是如果跟在其他值后,如6L或FRIL则表示该月中最后一个星期五。
    L还可以指定偏移量,如日域指定L-3,表示该月倒数第3天。当使用L时其值尽量不要指定列表或范围,以免令人困惑。

  • W:用于日域,表示距离指定日最近的星期几(周一至周五中的一个),如:日域上值为15W则表示距离本月第15日最近的工作日。

  • #:用于周域,表示该月的第n个星期几。如:周域值为6#3或FRI#3表示该月的第3个星期五。

附上:常用表达式示例

0 0 101416 * * ?每天上午10点、下午两点、下午4点整触发

0 0/30 9-17 * * ? 每天朝九晚五内每隔半小时触发

0 15 10 ? * MON-FRI 周一至周五的上午10:15触发

0 0/5 * * * ?5分钟触发

10 0/5 * * * ?每隔5分钟的第10秒触发(10:00:1010:05:1010:10:10)

30 * * * * ? 每半分钟触发

30 10 * * * ? 每小时的1030秒触发

30 10 1 * * ? 每天11030秒触发

30 10 1 20 * ? 每月2011030秒触发

30 10 1 20 10 ? * 每年102011030秒触发

30 10 1 20 10 ? 2011 2011102011030秒触发

30 10 1 ? 10 * 2011 201110月每天11030秒触发

30 10 1 ? 10 SUN 2011 201110月每周日11030秒触发

15,30,45 * * * * ?15秒,30秒,45秒时触发

15-45 * * * * ? 1545秒内,每秒都触发

15/5 * * * * ? 每分钟的每15秒开始触发,每隔5秒触发一次

15-30/5 * * * * ? 每分钟的15秒到30秒之间开始触发,每隔5秒触发一次

0 0/3 * * * ? 每小时的第00秒开始,每三分钟触发一次

0 15 10 ? * MON-FRI 星期一到星期五的10150秒触发

0 15 10 L * ? 每个月最后一天的10150秒触发

0 15 10 LW * ? 每个月最后一个工作日的10150秒触发

0 15 10 ? * 5L 每个月最后一个星期四的10150秒触发

0 15 10 ? * 5#3 每个月第三周的星期四的10150秒触发

参考博客:
https://blog.csdn.net/gnail_oug/article/details/80825302
https://blog.csdn.net/qq_27046951/article/details/82805259

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值