1、Quartz可以用来做什么?
Quartz是一个任务调度框架,比如你遇到这样的问题:
- 想每月25号,信用卡自动还款
- 想每年4月1日自动给当年暗恋女神发一封匿名贺卡
- 订单下单后未付款,15分钟后自动撤消订单,并自动解锁锁定的商品
这些问题总结起来就是:在某一个有规律的时间点干某件事。并且时间的触发的条件可以非常复杂(比如每月最后一个工作日的17:50),复杂到需要一个专门的框架来干这个事。 Quartz就是来干这样的事,你给它一个触发条件的定义,它负责到了时间点,触发相应的Job起来干活。
2、Quartz的触发器
触发器用来告诉调度程序作业什么时候触发,框架提供了5种触发器类型,但两个最常用的SimpleTrigger和CronTrigger。
五种类型的Trigger(定时器):SimpleTrigger,CronTirgger,DateIntervalTrigger,NthIncludedDayTrigger和Calendar类( org.quartz.Calendar)。
场景:
简单调度器(SimpleTrigger):执行N次,重复N次
表达式调度器(CronTrigger):几秒 几分 几时 哪日 哪月 哪周 哪年,执行
3、 存储方式
RAMJobStore(内存作业存储类型)和JDBCJobStore(数据库作业存储类型),两种方式对比如下:
quartz相关表达式:
在线生成表达式网址:http://cron.qqe2.com/
4、代码演示(包含简单调度器以及表达式触发器两类)
所需pom依赖:
<dependency>
<groupId>org.quartz-scheduler</groupId>
<artifactId>quartz-jobs</artifactId>
<version>2.2.1</version>
</dependency>
具体作业类代码:
package com.zking.job;
import org.quartz.*;
/**
* @author LJ
* @site www.lijun.com
* @Date 2019年02月23日
* @Time 19:20
*/
public class RamJob implements Job {
public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException {
System.out.println("定时任务启动。。。。");
JobDetail jobDetail = jobExecutionContext.getJobDetail();
JobDataMap jobDataMap = jobDetail.getJobDataMap();
System.out.println("定时任务参数:level-》" + jobDataMap.get("level") + ",name-》"
+ jobDataMap.get("name") + ",sex-》" + jobDataMap.get("sex"));
}
}
执行作业类逻辑:
public static void main(String[] args) throws SchedulerException {
//创建调度工厂类实例StdSchedulerFactory
StdSchedulerFactory sc = new StdSchedulerFactory();
//创建调度器实例Scheduler
Scheduler scheduler = sc.getScheduler();
//创建任务详情JobDetail
JobDetail jobDetail = newJob(RamJob.class)
.withIdentity("detail1","group1")//组成唯一标识
.withDescription("this is a jobDetail")
//向具体执行的作业类传值方式一
.usingJobData("level","admin")
.build();
//向具体执行的作业类传值方式二
JobDataMap jobDataMap = jobDetail.getJobDataMap();
jobDataMap.put("name","zs");
jobDataMap.put("sex","man");
Trigger trigger = TriggerBuilder.newTrigger()
.withIdentity("trigger1","group1")
.withDescription("this is a trigger")
//简单调度器:每四秒执行一次,共执行三次
.withSchedule(SimpleScheduleBuilder.repeatSecondlyForTotalCount(3,4))
//表达式调度器:每五秒执行一次
// .withSchedule(CronScheduleBuilder.cronSchedule("*/5 * * * * ?"))
.build();
//注入作业类以及触发器到调度器中
scheduler.scheduleJob(jobDetail,trigger);
//启动调度器
scheduler.start();
}
运行效果:
这个例子很好的覆盖了Quartz最重要的3个基本要素:
- Scheduler:调度器。所有的调度都是由它控制。
- Trigger: 定义触发的条件。
- JobDetail & Job: JobDetail 定义的是任务数据,而真正的执行逻辑是在Job中,例子中是RamJob。 为什么设计成JobDetail + Job,不直接使用Job?这是因为任务是有可能并发执行,如果Scheduler直接使用Job,就会存在对同一个Job实例并发访问的问题。而JobDetail & Job 方式,sheduler每次执行,都会根据JobDetail创建一个新的Job实例,这样就可以规避并发访问的问题。
5、spring自带的定时任务
缺点:单线程执行
package com.zking.job;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service;
/**
* @author LJ
* @site www.lijun.com
* @Date 2019年02月23日
* @Time 20:19
*/
@Service
public class SpringTask {
@Scheduled(cron = "0/5 * * * * ?")
public void test(){
System.out.println("测试spring自带的定时任务。。。。");
try {
Thread.sleep(10*1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("定时任务结束。。。。");
}
}
package com.zking;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.scheduling.annotation.EnableScheduling;
@EnableScheduling
@SpringBootApplication
public class Quartz01Application {
public static void main(String[] args) {
SpringApplication.run(Quartz01Application.class, args);
}
}