【定时任务】之Quartz的简单使用----基于内存的使用方式

一、依赖坐标

spring boot中使用quartz有两种方式,一种是基础的:引入quartz包与spring的上下文支持spring-context-support

         <!-- quartz -->
        <dependency>
            <groupId>org.quartz-scheduler</groupId>
            <artifactId>quartz</artifactId>
            <version>2.2.1</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context-support</artifactId>
            <version>5.0.10.RELEASE</version>
        </dependency>

另一种是直接使用starter,坐标为:

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-quartz</artifactId>
        </dependency>

但其实点进spring-boot-starter-quartz去看,其中同时引用了quartz和spring-context-support,相当于在外面包装了一层,是的引用更加方便而已。

二、Quartz的核心类

1、Job与JobDetail 任务

你想要调度器执行的任务组件需要实现Job接口,并重写其中唯一的方法execute,在其中写上任务要做的工作;JobDetail 则用于定义任务的实例,可以使用 JobBuilder 类中的静态方法来创建,例如:

JobDetail job = JobBuilder.newJob(PrintTask.class).build();

这里调用了newJob方法创建一个 JobDetail 实例,并指定使用 PrintTask 为实际要执行的任务类,PrintTask 类需要实现 Job 接口并重写 execute 方法,其代码如下:在execute中将会打印当前时间,并用"yyyy-MM-dd HH:mm:ss"来格式化。

public class PrintTask implements Job {

    @Override
    public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException {
        
        System.out.println(LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));

    }
}

此外,与Job/JobDetail相关的还有几个类,JobDataMap、JobKey等:

  • JobKey:由 name 和 group 两部分构成,用来唯一标识一个 Job,同一个 group 的两个 job 不可以有相同的 name,可以使用 withIdentity 方法将 key 绑定到 job上:
JobKey jobKey = new JobKey("printDateTimeJob", "printDateTime");
JobDetail job = newJob(PrintTask.class).withIdentity(jobKey).build();

或不使用 JobKey,直接将 name 和 group 用 withIdentity 绑定到 job 上

JobDetail job = JobBuilder.newJob(PrintTask.class).withIdentity("printDateTimeJob", "printDateTime").build();
  • JobDataMap:JobDataMap中可以包含不限量的(序列化的)数据对象,在job实例执行的时候,可以使用其中的数据;将job加入到scheduler之前,在构建JobDetail时,可以将数据放入JobDataMap,并在execute中使用 JobDataMap dataMap = jobExecutionContext.getJobDetail().getJobDataMap() 或者 jobExecutionContext.getMergedJobDataMap() 取出来使用,例如:
JobDataMap dataMap = new JobDataMap();
dataMap.put("flag", "ok");

JobKey jobKey = new JobKey("printDateTimeJob", "printDateTime");
JobDetail job = newJob(PrintTask.class).withIdentity(jobKey).usingJobData(dataMap).build();

在 PrintTask 中可以通过 JobExecutionContext 这样使用它:

public class PrintTask implements Job {

    @Override
    public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException {
        JobDataMap dataMap = jobExecutionContext.getJobDetail().getJobDataMap();
        String flag = dataMap.getString("flag");
        System.out.println("flag: " + flag);
        System.out.println(LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
    }
}

2、Trigger 触发器

常用的 Trigger 有两种类型,分别是 SimpleTrigger 和 CronTrigger,但他们也是有着部分相同的属性的:

  • triggerKey:与 JobTrigger 十分相似,同样是由 name 和 group 两部分构成,使用方式也同样可以使用 withIdentity 方法将 key 与 trigger 绑定
TriggerKey triggerKey = new TriggerKey("printDateTimeTrigger", "printDateTime");
Trigger trigger = TriggerBuilder.newTrigger().withIdentity(triggerKey).build();

或不使用 TriggerKey ,直接将 name 和 group 用 withIdentity 绑定到 trigger 上

Trigger trigger = TriggerBuilder.newTrigger().withIdentity("printDateTimeTrigger", "printDateTime").build();
  • startTime:设置 trigger 第一次触发的时间,是一个 java.util.Date 类型,具体用法会在后面的例子中体现
  • endTime:设置 trigger 失效的时间点
SimpleTrigger :

SimpleTrigger 可以满足的调度需求是在具体时间执行一次、或是从具体的时间点开始执行,以指定的时间间隔重复若干次。即 SimpleTrigger 的属性包括开始时间、结束时间、重复次数以及时间间隔,这几个属性进行组合可以实现一些简单的调度任务。
但要注意的是endTime这个属性的值会覆盖设置重复次数的属性值;比如,可以创建一个trigger,在终止时间之前每隔10秒执行一次,你不需要去计算在开始时间和终止时间之间的重复次数,只需要设置终止时间并将重复次数设置为REPEAT_INDEFINITELY(当然也可以将重复次数设置为一个很大的值,并保证该值比trigger在终止时间之前实际触发的次数要大即可)。

SimpleTrigger 可以用 TriggerBuilder 的静态方法很方便的构造,下面有几个例子展示 SimpleTrigger 创建调度的实际使用:

// 在5s后触发,不重复
Trigger trigger = TriggerBuilder.newTrigger()
        .startAt(DateBuilder.futureDate(5, DateBuilder.IntervalUnit.SECOND))
        .build();
// 在指定时间触发,不重复
Trigger trigger = TriggerBuilder.newTrigger()
        .startAt(someDate)
        .build();
// 在5s后触发,每1s执行一次,重复10次
Trigger trigger = TriggerBuilder.newTrigger()
        .startAt(DateBuilder.futureDate(5, DateBuilder.IntervalUnit.SECOND))
        .withSchedule(SimpleScheduleBuilder.simpleSchedule()
                .withIntervalInSeconds(1)
                .withRepeatCount(10))
        .build();
// 立即触发,每10分钟执行一次,直到22:00
Trigger trigger = TriggerBuilder.newTrigger()
        .withSchedule(SimpleScheduleBuilder.simpleSchedule().withIntervalInSeconds(1).withRepeatCount(10))
        .endAt(DateBuilder.dateOf(22, 0, 0))
        .build();

还有许多比较复杂的比如在下一个整点触发等用法,感兴趣的话可以自行查看文档以及源码来看具体的用法。

CronTrigger

如果需要基于日历的概念而不是按照SimpleTrigger的精确指定间隔进行重新启动的作业启动计划。则可以使用CronTrigger指定时间表,例如“每周五中午”或“每个工作日的上午9:30”,甚至“每周一至周五上午9:00至10点之间每5分钟”和1月份的星期五“等等。

CronTrigger由cron表达式配置,cron表达式可以分为七个部分,用空格分隔开,从左到右分别代表:秒(Seconds)、分钟(Minutes)、小时(Hours)、日(Day-of-Month)、月(Month)、周(Day-of-Week)、年(Year,为可选字段)
NOTE: cron表达式不在这里进行展开阐述,可以参考Cron表达式的详细用法 以及在线cron表达式生成器

下面直接用几个例子来体会 CronTrigger 的用法:

// 每天上午八点到下午六点,每30分钟执行一次
Trigger trigger = TriggerBuilder.newTrigger()
        .withSchedule(CronScheduleBuilder.cronSchedule("0 0/30 8-18 * * ? *"))
        .build();
// 每天中午11点50执行
Trigger trigger = TriggerBuilder.newTrigger()
        .withSchedule(CronScheduleBuilder.cronSchedule("0 50 11 * * ? *"))
        .build();

或不用cron表达式

Trigger trigger = TriggerBuilder.newTrigger()
        .withSchedule(CronScheduleBuilder.dailyAtHourAndMinute(11, 50))
        .build();
// 在指定时区的每周的星期五下午六点执行:
Trigger trigger1 = TriggerBuilder.newTrigger()
        .withSchedule(CronScheduleBuilder.cronSchedule("0 0 18 ? * WED")
                .inTimeZone(TimeZone.getTimeZone("Asia/Shanghai")))
        .build();

3、Scheduler 调度器

简单的使用可以通过 StdSchedulerFactory.getDefaultScheduler() 方法获取 scheduler 实例,默认使用的是SimpleThreadPool,可以通过配置文件等方式去修改默认的值。

// 可以通过 scheduleJob 的方式将 job 和 trigger 都关联起来,并使用 scheduler.start() 开始定时任务
// 需要关闭定时任务时,可以使用scheduler.shutdown()来关掉这个定时任务
scheduler.scheduleJob(job, trigger);
scheduler.start();
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值