目录
一、Quartz介绍
二、Quartz的组成
三、使用java实现一个简单的Quartz例子
四、使用Springboot整合Quartz定时任务框架
五、使用Springboot+mybatis整合Quartz定时任务框架实现定时向数据库插入一条数据
六、总结
七、参考资料
一、Quartz介绍
quartz是一种基于java实现的任务调度框架,可以定时自动的执行你想要执行的任何任务。
quartz官网:http://www.quartz-scheduler.org/
二、Quartz的组成
任务Job(你要做什么事?)
job就是你想要实现的任务类,每一个job必须实现org.quartz.job接口。
触发器Trigger(你什么时候去做?)
Trigger为你执行任务的触发器,比如你想每天定时3点发送一份统计邮件,Trigger将会设置3点进行执行该任务。
调度器Scheduler(你什么时候需要做什么事?)
Scheduler为任务的调度器,它会将任务job及触发器Trigger整合起来,负责基于Trigger设定的时间来执行Job。
三、使用java实现一个简单的Quartz例子
1、新建一个maven项目,并引入Quartz依赖 https://mvnrepository.com/search?q=quartz
pom.xml
<?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>org.example</groupId>
<artifactId>Quartz</artifactId>
<version>1.0-SNAPSHOT</version>
<dependencies>
<!--核心包-->
<dependency>
<groupId>org.quartz-scheduler</groupId>
<artifactId>quartz</artifactId>
<version>2.3.2</version>
</dependency>
<!--工具-->
<dependency>
<groupId>org.quartz-scheduler</groupId>
<artifactId>quartz-jobs</artifactId>
<version>2.3.2</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>1.7.7</version>
<scope>compile</scope>
</dependency>
</dependencies>
</project>
2、编写一个Job类,用来编写定时任务要做什么
package quartz.job;
import javafx.scene.chart.PieChart;
import org.quartz.Job;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
import java.text.SimpleDateFormat;
import java.util.Date;
public class HelloJob implements Job {
public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException {
//输出当前时间
Date date=new Date();
SimpleDateFormat dateFormat=new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
String dateString=dateFormat.format(date);
//工作内容
System.out.println("执行定时任务,时间是:"+dateString);
}
}
3、编写触发器和调度器
package quartz.job;
import org.quartz.*;
import org.quartz.impl.StdSchedulerFactory;
public class HelloSchedulerDemo {
public static void main(String[] args) throws Exception{
//1、调度器(Schedular),从工厂中获取调度实例(默认:实例化new StdSchedulerFactory();)
Scheduler scheduler= StdSchedulerFactory.getDefaultScheduler();
//2、任务实例(JobDetail)
JobDetail jobDetail= JobBuilder.newJob(HelloJob.class) //加载任务类,与HelloJob完成绑定,要求HelloJob实现Job接口
.withIdentity("job1","group1") //参数1:任务的名称(唯一实例);参数2:任务组的名称
.build();
//3、触发器(Trigger)
Trigger trigger= TriggerBuilder.newTrigger()
.withIdentity("trigger1","group1") //参数1:触发器的名称(唯一实例);参数2:触发器组的名称
.startNow() //马上启动触发器
.withSchedule(SimpleScheduleBuilder.repeatSecondlyForever(5)) //每5秒执行一次
.build();
//让调度器关联任务和触发器,保证按照触发器定义的条件执行任务
scheduler.scheduleJob(jobDetail,trigger);
//启动
scheduler.start();
}
}
执行结果:
四、使用Springboot整合Quartz定时任务框架
1、pom.xml
<?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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.2.3.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.springboot</groupId>
<artifactId>Quartz</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>erp</name>
<description>Quartz for Spring Boot</description>
<properties>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!--导入html依赖-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
<!--核心包-->
<dependency>
<groupId>org.quartz-scheduler</groupId>
<artifactId>quartz</artifactId>
<version>2.3.2</version>
<exclusions>
<exclusion>
<artifactId>slf4j-api</artifactId>
<groupId>org.slf4j</groupId>
</exclusion>
</exclusions>
</dependency>
<!--工具-->
<dependency>
<groupId>org.quartz-scheduler</groupId>
<artifactId>quartz-jobs</artifactId>
<version>2.3.2</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>1.7.7</version>
<!-- <scope>compile</scope>-->
</dependency>
<!--添加Scheduled坐标-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context-support</artifactId>
</dependency>
<!--Spring tx 坐标-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-tx</artifactId>
</dependency>
</dependencies>
</project>
2、 job类
package quartz.job;
import org.quartz.Job;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
import java.util.Date;
public class QuartzDemo implements Job {
@Override
public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException {
System.out.println("Execute..."+new Date());
}
}
3、配置类,配置触发器与任务调度器
package quartz.job;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.quartz.JobDetailFactoryBean;
import org.springframework.scheduling.quartz.SchedulerFactoryBean;
import org.springframework.scheduling.quartz.SimpleTriggerFactoryBean;
/**
* Quartz配置类
*/
@Configuration
public class QuartzConfig {
/**
* 1、创建Job对象
*/
@Bean
public JobDetailFactoryBean jobDetailFactoryBean(){
JobDetailFactoryBean factoryBean=new JobDetailFactoryBean();
//关联我们自己的Job类
factoryBean.setJobClass(QuartzDemo.class);
return factoryBean;
}
/**
* 2、创建Trigger对象
*/
@Bean
public SimpleTriggerFactoryBean simpleTriggerFactoryBean(JobDetailFactoryBean jobDetailFactoryBean){
SimpleTriggerFactoryBean factoryBean=new SimpleTriggerFactoryBean();
//关联JobDetail对象
factoryBean.setJobDetail(jobDetailFactoryBean.getObject());
//该参数表示一个执行的毫秒数
factoryBean.setRepeatInterval(2000); //每隔2秒执行一次
//重复次数
factoryBean.setRepeatCount(5);
return factoryBean;
}
/**
* 3、创建Scheduler
*/
@Bean
public SchedulerFactoryBean schedulerFactoryBean(SimpleTriggerFactoryBean simpleTriggerFactoryBean){
SchedulerFactoryBean factoryBean=new SchedulerFactoryBean();
//关联trigger
factoryBean.setTriggers(simpleTriggerFactoryBean.getObject());
return factoryBean;
}
}
4、启动类
package quartz.job;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.web.servlet.support.SpringBootServletInitializer;
import org.springframework.scheduling.annotation.EnableScheduling;
@SpringBootApplication
@EnableScheduling
public class QuartzApplication extends SpringBootServletInitializer {
public static void main(String[] args) {
SpringApplication.run(QuartzApplication.class, args);
}
}
执行结果:
每隔2秒执行一次执行5次
五、使用Springboot+mybatis整合Quartz定时任务框架实现定时向数据库插入一条数据
IDEA项目目录结构
pom.xml
<?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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.2.3.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.springboot</groupId>
<artifactId>Quartz</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>erp</name>
<description>Quartz for Spring Boot</description>
<properties>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!--导入html依赖-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
<!--核心包-->
<dependency>
<groupId>org.quartz-scheduler</groupId>
<artifactId>quartz</artifactId>
<version>2.3.2</version>
<exclusions>
<exclusion>
<artifactId>slf4j-api</artifactId>
<groupId>org.slf4j</groupId>
</exclusion>
</exclusions>
</dependency>
<!--工具-->
<dependency>
<groupId>org.quartz-scheduler</groupId>
<artifactId>quartz-jobs</artifactId>
<version>2.3.2</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>1.7.7</version>
<!-- <scope>compile</scope>-->
</dependency>
<!--添加Scheduled坐标-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context-support</artifactId>
</dependency>
<!--Spring tx 坐标-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-tx</artifactId>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>2.1.1</version>
</dependency>
</dependencies>
</project>
application.yml
server:
port: 8080
spring:
datasource:
name: mydb
url: jdbc:mysql://localhost:3306/mydb?useUnicode=true&characterEncoding=utf-8&useSSL=true&serverTimezone=Hongkong
username: root
password: 123456
driver-class-name: com.mysql.cj.jdbc.Driver
mybatis:
mapper-locations: classpath:Mapper/*.xml #注意:一定要对应mapper映射xml文件的所在路径
type-aliases-package: com.springboot.quartz.Entity # 注意:对应实体类的路径
QuartzDemoMapper类
package com.springboot.quartz.Mapper;
import com.springboot.quartz.Entity.QuartzDemo;
import org.apache.ibatis.annotations.Insert;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
import org.springframework.stereotype.Component;
@Mapper
@Component
public interface QuartzDemoMapper {
@Insert("insert into QuartzDemo (op_time,operation) values (#{op_time},#{operation})")
void insertQuartzDemo(java.sql.Timestamp op_time,String operation);
@Insert("insert into QuartzDemo_1 (operation) values (#{operation})")
void insertQuartzDemo_1(String operation);
/* // @Param注解的作用是给参数命名,参数命名后就能根据名字得到参数值,正确的将参数传入sql语句中
QuartzDemo insertQuartzDemo(@Param("o_ptime") java.sql.Timestamp op_time, @Param("operation") String operation);*/
}
QuartzDemoService类
package com.springboot.quartz.Service;
import com.springboot.quartz.Mapper.QuartzDemoMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@Service
public class QuartzDemoService {
@Autowired
private QuartzDemoMapper quartzDemoMapper;
public void insertQuartzDemo(java.sql.Timestamp op_time,String operation){
quartzDemoMapper.insertQuartzDemo(op_time,operation);
}
public void insertQuartzDemo_1(String operation){
quartzDemoMapper.insertQuartzDemo_1(operation);
}
}
Job类
package com.springboot.quartz.job;
import com.springboot.quartz.Service.QuartzDemoService;
import org.quartz.Job;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
@Component
public class QuartzDemoJob implements Job {
static int i = 0;
@Autowired
private QuartzDemoService quartzDemoService;
public QuartzDemoJob() {
}
@Autowired //这里不能直接注入,因为@Autowired注入是Spring的注入,要求注入对象与被注入对象都是在SpringIOC容器中存在,
public QuartzDemoJob(QuartzDemoService quartzDemoService) {
this.quartzDemoService = quartzDemoService;
}
@Override
public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException {
String operation = "测试" + i++;
Date current_time = new Date();
String strDate = dateToStr(current_time, "yyyy-MM-dd HH:mm:ss");
java.sql.Timestamp op_time = strToSqlDate(strDate, "yyyy-MM-dd HH:mm:ss");
quartzDemoService.insertQuartzDemo(op_time, operation);
System.out.println(op_time + "------" + operation);
}
public static String dateToStr(java.util.Date date, String strFormat) {
SimpleDateFormat sf = new SimpleDateFormat(strFormat);
String str = sf.format(date);
return str;
}
public static java.sql.Timestamp strToSqlDate(String strDate, String dateFormat) {
SimpleDateFormat sf = new SimpleDateFormat(dateFormat);
java.util.Date date = null;
try {
date = sf.parse(strDate);
} catch (ParseException e) {
e.printStackTrace();
}
java.sql.Timestamp dateSQL = new java.sql.Timestamp(date.getTime());
return dateSQL;
}
}
编写Job类时要注意,Job类默认是通过AdaptableJobFactory类的createJobInstance通过newInstance()反射进行实例化的,因此没有经过Spring的处理。所以QuartzDemoJob默认是不在SpringIOC容器中的,因此@Autowired注解无法在QuartzDemoJob类中直接注入到SpringIOC容器中。
注意:QuartzDemoJob类中一定要有无参构造方法,否则Job配置类中getObject()这块会报错!
因此我们需要手动的把QuartzDemoJob类注入到SpringIOC容器中。
编写一个类MyAdaptableJobFactory继承AdaptableJobFactory,覆盖createJobInstance()方法。
MyAdaptableJobFactory类
package com.springboot.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;
@Component("myadaptableJobFactory") //将该类实例化,使得可以直接用
public class MyadaptableJobFactory extends AdaptableJobFactory {
//AutowireCapableBeanFactory可以将一个对象添加到Spring IOC容器中,并且完成该对象注入
@Autowired
private AutowireCapableBeanFactory autowireCapableBeanFactory;
//该方法将实例化的任务对象手动的添加到SpringIOC容器中并且完成对象的注入
@Override
protected Object createJobInstance(TriggerFiredBundle bundle) throws Exception {
Object object = super.createJobInstance(bundle);
//将object对象添加到Spring IOC容器中并完成注入
this.autowireCapableBeanFactory.autowireBean(object);
return object;
}
}
Quartz配置类
package com.springboot.quartz.Config;
import com.springboot.quartz.job.QuartzDemoJob;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.quartz.CronTriggerFactoryBean;
import org.springframework.scheduling.quartz.JobDetailFactoryBean;
import org.springframework.scheduling.quartz.SchedulerFactoryBean;
import org.springframework.scheduling.quartz.SimpleTriggerFactoryBean;
/**
* Quartz配置类
*/
@Configuration
public class QuartzConfig {
/**
* 1、创建Job对象
*/
@Bean
public JobDetailFactoryBean jobDetailFactoryBean(){
JobDetailFactoryBean factoryBean=new JobDetailFactoryBean();
//关联我们自己的Job类
factoryBean.setJobClass(QuartzDemoJob.class); //QuartzDemoJob的实例化并没有经过Spring的处理,
// Spring的注入是要求注入的对象和被注入的对象都要在Spring的IOC容器中
return factoryBean;
}
/**
* 2、创建Trigger对象
* Cron Trigger
*/
@Bean
public CronTriggerFactoryBean cronTriggerFactoryBean(JobDetailFactoryBean jobDetailFactoryBean){
CronTriggerFactoryBean factoryBean=new CronTriggerFactoryBean();
//关联JobDetail对象
factoryBean.setJobDetail(jobDetailFactoryBean.getObject());
//设置触发时间
//factoryBean.setCronExpression("0/2 * * * * ?"); //每2秒触发一次, 分钟,小时,天,月,星期
factoryBean.setCronExpression("0 0-59 0-22 * * ?"); //在每天0-22点期间的每1分钟触发
return factoryBean;
}
/**
* 3、创建Scheduler
*/
@Bean
public SchedulerFactoryBean schedulerFactoryBean(CronTriggerFactoryBean cronTriggerFactoryBean, MyadaptableJobFactory myadaptableJobFactory){
SchedulerFactoryBean factoryBean=new SchedulerFactoryBean();
//关联trigger
factoryBean.setTriggers(cronTriggerFactoryBean.getObject());
factoryBean.setJobFactory(myadaptableJobFactory); //调用myadaptableJobFactory把对象注入到SpringIOC容器中
return factoryBean;
}
}
setCronExpression()方法可以设置定时器触发时间,具体设置规则可以参考下图
启动类
package com.springboot.quartz;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.web.servlet.support.SpringBootServletInitializer;
import org.springframework.scheduling.annotation.EnableScheduling;
@EnableScheduling
@SpringBootApplication
/*@MapperScan("com.springboot.quartz.Mapper")*/
public class QuartzApplication extends SpringBootServletInitializer {
public static void main(String[] args) {
SpringApplication.run(QuartzApplication.class, args);
}
}
执行结果:
写入的数据库
六、总结
quartz定时任务是由Job、Trigger和Scheduler三部分组成。Job里面写定时任务的具体做什么,Trigger设定定时任务的执行时间,Scheduler则负责整个定时任务的调度。java单一使用quartz框架比较简单。如果是Spring配置quartz则要注意Job的注入问题。因为默认Job是由AdaptableJobFactory类中的createJobInstance方法进行实例化因此不会在SpringIOC中的,所以需要覆盖AdaptableJobFactory类中的createJobInstance方法,手动将Job对象注入到SpringIOC容器中。