前言

有时候需要实现动态定时任务,即工程启动后,可以实现启动和关闭任务,同时也可以设置定时计划。这就需要利用到quartz

别的先不多说,先利用配置文件制作一个简单的定时器器吧

1、利用配置文件配置定时器(很少,以后还会详解)

1.1 、导入pom依赖

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>

<groupId>com.hlj.quartz</groupId>
<artifactId>com-hlj-quartz</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>jar</packaging>

<name>com-hlj-quartz</name>
<description>Demo project for Spring Boot</description>

<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.0.0.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>

<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<java.version>1.8</java.version>
</properties>

<dependencies>

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

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

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

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

</dependencies>

<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>

1.2、resource下创建配置文件quartz.properties

#scheduler实例名称。
org.quartz.scheduler.instanceName =MyScheduler
#配置线程池的容量,即表示同时最多可运行的线程数量
org.quartz.threadPool.threadCount =3
#job存储方式,RAMJobStore是使用JobStore最简单的一种方式,它也是性能最高效的,顾名思义,JobStore是把它的数据都存储在RAM中,
# 这也是它的快速和简单配置的原因;JDBCJobStore也是一种相当有名的JobStore,它通过JDBC把数据都保存到数据库中,
# 所以在配置上会比RAMJobStore复杂一些,而且不像RAMJobStore那么快,但是当我们对数据库中的表的主键创建索引时,性能上的缺点就不是很关键的了。
org.quartz.jobStore.class = org.quartz.simpl.RAMJobStore

1.3、新建一个定时器任务

继承Job类,也就是工作任务类,然后重写里面的方法 ​​execute​

package com.hlj.quartz.quartz.Job;
import java.util.Date;
import org.quartz.Job;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;


/**
* @Description 任务类.
* @Author HealerJean
* @Date 2018/3/22 下午4:17.
*/

public class HelloJobOne implements Job{

public void execute(JobExecutionContext context) throws JobExecutionException {
System.out.println("一号任务"+new Date());

}
}

1.4、service中开始调用执行这个job

解释:

1、其实配置文件中配置的,也就是我们可以在下面使用的定时器了,也就是获取实例

Scheduler scheduler = StdSchedulerFactory.getDefaultScheduler();

2、定时器有了,下一步就是获取上面的任务,也就是获取工作详情

JobDetail jobDetail = JobBuilder.newJob(HelloJobOne.class).withIdentity("job1","group1").build();

3、工作任务有了,那么下一布,就是工作的执行时间和触发规则,交给定时器

SimpleScheduleBuilder simpleScheduleBuilder = SimpleScheduleBuilder.simpleSchedule().withIntervalInSeconds(5).repeatForever();
Trigger trigger = TriggerBuilder.newTrigger().withIdentity("trigger1","group1").startNow().withSchedule(simpleScheduleBuilder).build();
// 交由Scheduler安排触发
scheduler.scheduleJob(jobDetail,trigger);

下面是service全部代码


public void haveProperties() throws SchedulerException, InterruptedException{
/*
*在 Quartz 中, scheduler 由 scheduler 工厂创建:
* DirectSchedulerFactory 或者 StdSchedulerFactory。
*第二种工厂 StdSchedulerFactory 使用较多,
*因为 DirectSchedulerFactory 使用起来不够方便,需要作许多详细的手工编码设置。
*/
// 获取Scheduler实例
Scheduler scheduler = StdSchedulerFactory.getDefaultScheduler();
scheduler.start();
System.out.println("scheduler.start");
//具体任务.
JobDetail jobDetail = JobBuilder.newJob(HelloJobOne.class).withIdentity("job1","group1").build();
//触发时间点. (每5秒执行1次.)
SimpleScheduleBuilder simpleScheduleBuilder = SimpleScheduleBuilder.simpleSchedule().withIntervalInSeconds(5).repeatForever();
Trigger trigger = TriggerBuilder.newTrigger().withIdentity("trigger1","group1").startNow().withSchedule(simpleScheduleBuilder).build();
// 交由Scheduler安排触发
scheduler.scheduleJob(jobDetail,trigger);
//睡眠20秒.
TimeUnit.SECONDS.sleep(20);
scheduler.shutdown();//关闭定时任务调度器.
System.out.println("scheduler.shutdown");

}

1.5、controler中开始调用


/**
* @Desc 有配置文件quartz.properties
* @Date 2018/3/22 下午5:40.
*/

@GetMapping("haveProperties")
public String haveProperties() throws InterruptedException, SchedulerException {
quartzService.haveProperties();
return "使用配置文件-定时器开始执行,请观察控制台";
}

1.6、浏览器中访问吧,朋友

​http://localhost:8080/haveProperties​

调用的时候可以看到控制台关于,配置文件 quartz.properties 中的一些信息。 而且人物执行成功

[外链图片转存失败(img-K9WyKiY3-1566552781868)(https://raw.githubusercontent.com/HealerJean123/HealerJean123.github.io/master/blogImages/WX20180322-191414.png)]

2、没有配置文件,但是很牛逼的真正的quartz

2.1、定义一个工作工厂,​​JobFactory​

package com.hlj.quartz.quartz.config;

import org.quartz.spi.TriggerFiredBundle;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.config.AutowireCapableBeanFactory;
import org.springframework.scheduling.quartz.AdaptableJobFactory;
import org.springframework.stereotype.Component;

/**
* @Description
* @Author HealerJean
* @Date 2018/3/22 下午3:43.
*/
@Component
public class JobFactory extends AdaptableJobFactory {
@Autowired
private AutowireCapableBeanFactory capableBeanFactory;

@Override
protected Object createJobInstance(TriggerFiredBundle bundle) throws Exception {
//调用父类的方法
Object jobInstance = super.createJobInstance(bundle);
//进行注入
capableBeanFactory.autowireBean(jobInstance);
return jobInstance;
}
}

2.2、开始从定时器工厂中,找到定时器Bean

package com.hlj.quartz.quartz.config;

import org.quartz.Scheduler;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.quartz.SchedulerFactoryBean;


/**
* @Description
* @Author HealerJean
* @Date 2018/3/22 下午3:45.
*/
@Configuration
public class QuartzConfig {

@Autowired
private JobFactory jobFactory;


@Bean
public SchedulerFactoryBean schedulerFactoryBean() {
SchedulerFactoryBean schedulerFactoryBean = new SchedulerFactoryBean();
schedulerFactoryBean.setOverwriteExistingJobs(true);
schedulerFactoryBean.setJobFactory(jobFactory);
return schedulerFactoryBean;
}


// 创建schedule
@Bean(name = "scheduler")
public Scheduler scheduler() {
return schedulerFactoryBean().getScheduler();
}

}

2.3、这个时候,我们开始一系列的方法,对定时器进行了解

实话实说,我看的比较着急,还没有对定时器自己的一些方法进行仔细深入的了解

1、这时,我们可以看到这里用到的其实就是固定时间的定时器(可以设置为某一天的几点开始执行) ,上面的定时器是没几秒开始执行。所以二者是有区别的,具体如下

SimpleScheduleBuilder是简单调用触发器,它只能指定触发的间隔时间和执行次数

CronScheduleBuilder是类似于Linux Cron的触发器,它通过一个称为CronExpression的规则来指定触发规则,通常是每次触发的具体时间;

CalendarIntervalScheduleBuilder是对CronScheduleBuilder的补充,它能指定每隔一段时间触发一次。

2、针对暂停,和关闭任务,也是是利用触发规则的name和group,然后判断这个规则是否存在工作,如果存在则执行定时器

3、下面我设置了两个任务。controller中对这两个任务进行观察

package com.hlj.quartz.quartz.service;

import com.hlj.quartz.quartz.Job.HelloJobOne;
import org.quartz.*;
import org.quartz.impl.StdSchedulerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.concurrent.TimeUnit;

/**
* @Description
* @Author HealerJean
* @Date 2018/3/22 下午4:38.
*/
/**
SimpleScheduleBuilder是简单调用触发器,它只能指定触发的间隔时间和执行次数;
CronScheduleBuilder是类似于Linux Cron的触发器,它通过一个称为CronExpression的规则来指定触发规则,通常是每次触发的具体时间;(关于CronExpression,详见:官方,中文网文)
CalendarIntervalScheduleBuilder是对CronScheduleBuilder的补充,它能指定每隔一段时间触发一次。
*/

@Service
public class QuartzService {

@Autowired
private Scheduler scheduler;

public void startJob(String time,String jobName,String group,Class job){
try {
// 创建jobDetail实例,绑定Job实现类
// 指明job的名称,所在组的名称,以及绑定job类
JobDetail jobDetail = JobBuilder.newJob(job).withIdentity(jobName, group).build();//设置Job的名字和组
//corn表达式 每2秒执行一次
CronScheduleBuilder scheduleBuilder = CronScheduleBuilder.cronSchedule(time/*"0/2 * * * * ?"*/);
//设置定时任务的时间触发规则
CronTrigger cronTrigger = TriggerBuilder.newTrigger().withIdentity(jobName,group) .withSchedule(scheduleBuilder).build();
System.out.println(scheduler.getSchedulerName());
// 把作业和触发器注册到任务调度中, 启动调度
scheduler.scheduleJob(jobDetail,cronTrigger);
/*
// 启动调度
scheduler.start();
Thread.sleep(30000);
// 停止调度
scheduler.shutdown();*/
} catch (Exception e) {
e.printStackTrace();
}
}

public void startJob2(String time,String jobName,String group,Class job){
try {
JobDetail jobDetail = JobBuilder.newJob(job).withIdentity(jobName, group).build();//设置Job的名字和组
CronScheduleBuilder scheduleBuilder = CronScheduleBuilder.cronSchedule(time/*"0/2 * * * * ?"*/);
CronTrigger cronTrigger = TriggerBuilder.newTrigger().withIdentity(jobName,group) .withSchedule(scheduleBuilder).build();
System.out.println(scheduler.getSchedulerName());
scheduler.scheduleJob(jobDetail,cronTrigger);
} catch (Exception e) {
e.printStackTrace();
}
}

/****
* 暂停一个任务
* @param triggerName
* @param triggerGroupName
*/
public void pauseJob(String triggerName,String triggerGroupName){
try {
JobKey jobKey = new JobKey(triggerName, triggerGroupName);
JobDetail jobDetail = scheduler.getJobDetail(jobKey);
if (jobDetail==null){
return;
}
System.out.println("开始暂停一个定时器");
scheduler.pauseJob(jobKey);
} catch (SchedulerException e) {
e.printStackTrace();
}
}

/****
* 暂停重启一个定时器任务
* @param triggerName
* @param triggerGroupName
*/
public void resumeJob(String triggerName,String triggerGroupName){
try {
JobKey jobKey = new JobKey(triggerName, triggerGroupName);
JobDetail jobDetail = scheduler.getJobDetail(jobKey);
if (jobDetail==null){
return;
}
scheduler.resumeJob(jobKey);
} catch (SchedulerException e) {
e.printStackTrace();
}
}



/****
* 删除一个定时器任务,删除了,重启就没什么用了
* @param triggerName
* @param triggerGroupName
*/
public void deleteJob(String triggerName,String triggerGroupName){
try {
JobKey jobKey = new JobKey(triggerName, triggerGroupName);
JobDetail jobDetail = scheduler.getJobDetail(jobKey);
if (jobDetail==null){
return;
}
scheduler.deleteJob(jobKey);
} catch (SchedulerException e) {
e.printStackTrace();
}
}




/***
* 根据出发规则匹配任务,立即执行定时任务,暂停的时候可以用
*/
public void doJob(String triggerName,String triggerGroupName){
try {
JobKey jobKey = JobKey.jobKey(triggerName, triggerGroupName);
scheduler.triggerJob(jobKey);
} catch (SchedulerException e) {
e.printStackTrace();
}
}


/***
* 开启定时器,这时才可以开始所有的任务,默认是开启的
*/
public void startAllJob(){
try {
scheduler.start();
} catch (SchedulerException e) {
e.printStackTrace();
}
}

/**
* 关闭定时器,则所有任务不能执行和创建
*/
public void shutdown(){
try {
scheduler.shutdown();
} catch (SchedulerException e) {
e.printStackTrace();
}
}

2.4、controller控制执行,注意观察控制台

package com.hlj.quartz.controller;

import com.hlj.quartz.quartz.Job.HelloJoTwo;
import com.hlj.quartz.quartz.service.QuartzService;
import com.hlj.quartz.quartz.Job.HelloJobOne;
import org.quartz.SchedulerException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;


/**
* @Description
* @Author HealerJean
* @Date 2018/3/22 下午4:47.
*/
@RestController
public class QuartzController {


@Autowired
private QuartzService quartzService;


@GetMapping("quartzStart")
public String startNNoQuartz(){
quartzService.startJob("0/1 * * * * ? ","job1","gropu1", HelloJobOne.class);
quartzService.startJob("0/2 * * * * ? ","job2","gropu2", HelloJoTwo.class);

return "定时器任务开始执行,请注意观察控制台";
}

@GetMapping("pauseJob")
public String pauseJob(){
quartzService.pauseJob("job1","gropu1");
return "暂停一个定时器任务,请注意观察控制台";
}


@GetMapping("resumeJob") //shutdown关闭了,或者删除了就不能重启了
public String resumeJob(){
quartzService.resumeJob("job1","gropu1");
return "暂停重启一个定时器任务,请注意观察控制台";
}

@GetMapping("deleteJob")
public String deleteJob(){
quartzService.deleteJob("job1","gropu1");
return "删除一个定时器任务,请注意观察控制台,删除了,重启就没什么用了";
}



@GetMapping("doJob")
public String doJob(){
quartzService.doJob("job1","gropu1");
return "根据出发规则匹配任务,立即执行定时任务,暂停的时候可以用";
}

@GetMapping("startAllJob")
public String startAllJob(){
quartzService.startAllJob();
return "开启定时器,这时才可以开始所有的任务,默认是开启的";
}

@GetMapping("shutdown")
public String shutdown(){
quartzService.shutdown();
return "关闭定时器,则所有任务不能执行和创建";
}


2.5、日期的匹配规则

表达式

允许值

“0 0 12 * * ?”

每天中午12点触发

“0 15 10 ? * *”

每天上午10:15触发

“0 15 10 * * ?”

每天上午10:15触发

“0 15 10 * * ? *”

每天上午10:15触发

“0 15 10 * * ? 2005”

2005年的每天上午10:15触发

“0 * 14 * * ?”

在每天下午2点到下午2:59期间的每1分钟触发

“0 0/5 14 * * ?”

在每天下午2点到下午2:55期间的每5分钟触发

“0 0/5 14,18 * * ?”

在每天下午2点到2:55期间和下午6点到6:55期间的每5分钟触发

“0 0-5 14 * * ?”

在每天下午2点到下午2:05期间的每1分钟触发

“0 10,44 14 ? 3 WED”

每年三月的星期三的下午2:10和2:44触发

“0 15 10 ? * MON-FRI”

周一至周五的上午10:15触发

“0 15 10 15 * ?”

每月15日上午10:15触发

“0 15 10 L * ?”

每月最后一日的上午10:15触发

“0 15 10 ? * 6L”

每月的最后一个星期五上午10:15触发

“0 15 10 ? * 6L 2002-2005”

2002年至2005年的每月的最后一个星期五上午10:15触发

“0 15 10 ? * 6#3”

每月的第三个星期五上午10:15触发

0 6 * * *

每天早上6点

0 /2 * *

每两个小时

0 23-7/2,8 * * *

晚上11点到早上8点之间每两个小时,早上八点

0 11 4 * 1-3

每个月的4号和每个礼拜的礼拜一到礼拜三的早上11点

0 4 1 1 *

1月1日早上4点

​代码下载​


2、SpringBoot集成Quartz_ide