目录
一、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 {@Overridepublic 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对象*/@Beanpublic JobDetailFactoryBean jobDetailFactoryBean(){JobDetailFactoryBean factoryBean=new JobDetailFactoryBean();//关联我们自己的Job类factoryBean.setJobClass(QuartzDemo.class);return factoryBean;}/*** 2、创建Trigger对象*/@Beanpublic SimpleTriggerFactoryBean simpleTriggerFactoryBean(JobDetailFactoryBean jobDetailFactoryBean){SimpleTriggerFactoryBean factoryBean=new SimpleTriggerFactoryBean();//关联JobDetail对象factoryBean.setJobDetail(jobDetailFactoryBean.getObject());//该参数表示一个执行的毫秒数factoryBean.setRepeatInterval(2000); //每隔2秒执行一次//重复次数factoryBean.setRepeatCount(5);return factoryBean;}/*** 3、创建Scheduler*/@Beanpublic SchedulerFactoryBean schedulerFactoryBean(SimpleTriggerFactoryBean simpleTriggerFactoryBean){SchedulerFactoryBean factoryBean=new SchedulerFactoryBean();//关联triggerfactoryBean.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: mydburl: jdbc:mysql://localhost:3306/mydb?useUnicode=true&characterEncoding=utf-8&useSSL=true&serverTimezone=Hongkongusername: rootpassword: 123456driver-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 {@Autowiredprivate 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;@Autowiredprivate QuartzDemoService quartzDemoService;public QuartzDemoJob() {}@Autowired //这里不能直接注入,因为@Autowired注入是Spring的注入,要求注入对象与被注入对象都是在SpringIOC容器中存在,public QuartzDemoJob(QuartzDemoService quartzDemoService) {this.quartzDemoService = quartzDemoService;}@Overridepublic 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容器中,并且完成该对象注入@Autowiredprivate AutowireCapableBeanFactory autowireCapableBeanFactory;//该方法将实例化的任务对象手动的添加到SpringIOC容器中并且完成对象的注入@Overrideprotected 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对象*/@Beanpublic JobDetailFactoryBean jobDetailFactoryBean(){JobDetailFactoryBean factoryBean=new JobDetailFactoryBean();//关联我们自己的Job类factoryBean.setJobClass(QuartzDemoJob.class); //QuartzDemoJob的实例化并没有经过Spring的处理,// Spring的注入是要求注入的对象和被注入的对象都要在Spring的IOC容器中return factoryBean;}/*** 2、创建Trigger对象* Cron Trigger*/@Beanpublic 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*/@Beanpublic SchedulerFactoryBean schedulerFactoryBean(CronTriggerFactoryBean cronTriggerFactoryBean, MyadaptableJobFactory myadaptableJobFactory){SchedulerFactoryBean factoryBean=new SchedulerFactoryBean();//关联triggerfactoryBean.setTriggers(cronTriggerFactoryBean.getObject());factoryBean.setJobFactory(myadaptableJobFactory); //调用myadaptableJobFactory把对象注入到SpringIOC容器中return factoryBean;}
}
setCronExpression()方法可以设置定时器触发时间,具体设置规则可以参考下图
图片来源:https://blog.csdn.net/fxj8291247/article/details/52329946
启动类
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容器中。
七、参考资料
https://www.bilibili.com/video/BV19t41127de?from=search&seid=2343824906917884403
https://www.bilibili.com/video/BV1mE411F7NJ?p=6
https://blog.csdn.net/fxj8291247/article/details/52329946
https://bbs.csdn.net/topics/360004856
https://blog.csdn.net/u012373815/article/details/86740625
https://blog.csdn.net/womeng2009/article/details/80328544