最近用到了quartz,简单的整理一下quartz的知识点,并学习网上的知识来做了一个比较简单的例子
quartz简介
- Scheduler - 与调度程序交互的主要API。
- Job - 由希望由调度程序执行的组件实现的接口。
- Trigger(即触发器) - 定义执行给定作业的计划的组件。
简单来说quartz就是由这三部分组成,我们首先定义job,即定时任务工作的内容,其次是trigger,即触发的时间,最后我们将前两者交给scheduler进行管理
quartz和springboot自带定时的区别
当使用springboot自带定时时,我选择将cron储存到数据库中,然后让定时任务访问数据库获得Trigger,但springboot有一个不足,那就是它只会在下次触发时间才会去访问数据库并通过数据库的cron来改变定时,想要实时改变异常困难.而quartz访问数据库的定时只会使用一次,也就是quartz启动的那一次,之后你改变数据库,并不会影响quartz,你只能调用quartz的方法来改变定时时间
quartz实例
SchedulerQuartzJob
此类为任务类,即本次定时任务我们要完成的功能,考虑到实际的情况,我在下面的例子中安排了三种场景:
-
输出一句简单的话
-
获得从前面传来的参数,并输出
-
通过spring的依赖注入,获得一个service层或者mapper层的对象,用来操作数据库
其中依赖注入因为quartz的原因不能成功,因此暂时注释掉,解决方案请往后看
import org.quartz.Job;
import org.quartz.JobDataMap;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
public class SchedulerQuartzJob implements Job {
//@Autowired
//private MailJobMapper mailJobMapper;
@Override
public void execute(JobExecutionContext context) throws JobExecutionException {
JobDataMap dataMap = context.getJobDetail().getJobDataMap();
String word = dataMap.getString("word"); //通过此我们可以获得前面传来的参数
System.out.println("学习使用quartz"+word);
//mailJobMapper.selsectByPrimaryKey(1);
}
}
QuartzSchedulerNew
此类是最重要的类,我们定义job和trigger,并交给scheduler管理,并对外提供start,delete.modify等控制定时任务的方法
import org.quartz.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.stereotype.Component;
import java.util.Date;
@Component
@Configuration
public class QuartzSchedulerNew {
// @Autowired
// private MailJobMapper mailJobMapper;
// 任务调度
@Autowired
private Scheduler scheduler;
/**
* 开始执行所有任务
*/
public void startJob() throws SchedulerException {
startJob(scheduler);
scheduler.start();
}
/**
* 获取Job信息
*/
public String getJobInfo(String name, String group) throws SchedulerException {
TriggerKey triggerKey = new TriggerKey(name, group);
CronTrigger cronTrigger = (CronTrigger) scheduler.getTrigger(triggerKey);
return String.format("time:%s,state:%s", cronTrigger.getCronExpression(),
scheduler.getTriggerState(triggerKey).name());
}
/**
* 修改某个任务的执行时间
*/
public boolean modifyJob(String name, String group, String time) throws SchedulerException {
Date date = null;
TriggerKey triggerKey = new TriggerKey(name, group);
CronTrigger cronTrigger = (CronTrigger) scheduler.getTrigger(triggerKey);
String oldTime = cronTrigger.getCronExpression();
if (!oldTime.equalsIgnoreCase(time)) {
CronScheduleBuilder cronScheduleBuilder = CronScheduleBuilder.cronSchedule(time);
CronTrigger trigger = TriggerBuilder.newTrigger().withIdentity(name, group)
.withSchedule(cronScheduleBuilder).build();
date = scheduler.rescheduleJob(triggerKey, trigger);
}
return date != null;
}
/**
* 暂停所有任务
*/
public void pauseAllJob() throws SchedulerException {
scheduler.pauseAll();
}
/**
* 暂停某个任务
*/
public void pauseJob(String name, String group) throws SchedulerException {
JobKey jobKey = new JobKey(name, group);
JobDetail jobDetail = scheduler.getJobDetail(jobKey);
if (jobDetail == null)
return;
scheduler.pauseJob(jobKey);
}
/**
* 恢复所有任务
*/
public void resumeAllJob() throws SchedulerException {
scheduler.resumeAll();
}
/**
* 恢复某个任务
*/
public void resumeJob(String name, String group) throws SchedulerException {
JobKey jobKey = new JobKey(name, group);
JobDetail jobDetail = scheduler.getJobDetail(jobKey);
if (jobDetail == null)
return;
scheduler.resumeJob(jobKey);
}
/**
* 删除某个任务
*/
public void deleteJob(String name, String group) throws SchedulerException {
JobKey jobKey = new JobKey(name, group);
JobDetail jobDetail = scheduler.getJobDetail(jobKey);
if (jobDetail == null)
return;
scheduler.deleteJob(jobKey);
}
private void startJob(Scheduler scheduler) throws SchedulerException {
// 通过JobBuilder构建JobDetail实例,JobDetail规定只能是实现Job接口的实例
// JobDetail 是具体Job实例
JobDetail jobDetail = JobBuilder
.newJob(SchedulerQuartzJob.class)
.withIdentity("job1", "group1")
.usingJobData("word", "Hello,World")//可以往ScheduleQuartzJob传参
.build();
// 基于表达式构建触发器
CronScheduleBuilder cronScheduleBuilder = CronScheduleBuilder.cronSchedule("0 1 * * * ?");//mailJob.getCron()
// CronTrigger表达式触发器 继承于Trigger
// TriggerBuilder 用于构建触发器实例
CronTrigger cronTrigger = TriggerBuilder
.newTrigger()
.withIdentity("job1", "group1")
.withSchedule(cronScheduleBuilder)
.build();
scheduler.scheduleJob(jobDetail, cronTrigger);
}
}
ApplicationStartQuartzJobListener
此类的作用为监听spring,是我们在任务一启动就可以开启定时任务
import org.quartz.Scheduler;
import org.quartz.SchedulerException;
import org.quartz.SchedulerFactory;
import org.quartz.impl.StdSchedulerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationListener;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.event.ContextRefreshedEvent;
import org.springframework.stereotype.Component;
@Configuration
@Component
public class ApplicationStartQuartzJobListener implements ApplicationListener<ContextRefreshedEvent> {
@Autowired
private QuartzSchedulerNew quartzSchedulerNew;
/**
* 初始启动quartz
*/
@Override
public void onApplicationEvent(ContextRefreshedEvent event) {
try {
quartzSchedulerNew.startJob();
System.out.println("quartz初始化中.......");
} catch (SchedulerException e) {
e.printStackTrace();
}
}
/**
* 初始注入scheduler
* @return
* @throws SchedulerException
*/
@Bean
public Scheduler scheduler() throws SchedulerException{
SchedulerFactory schedulerFactoryBean = new StdSchedulerFactory();
return schedulerFactoryBean.getScheduler();
}
}
QuartzApiController
我们对外提供url,调用定时任务的各个方法,这样就能让我们实时控制我们的定时任务
@RestController
@RequestMapping("/quartz")
public class QuartzApiController {
@Autowired
private QuartzSchedulerNew quartzSchedulerNew;
@RequestMapping("/start")
public void startQuartzJob() {
try {
quartzSchedulerNew.startJob();
} catch (SchedulerException e) {
e.printStackTrace();
}
}
@RequestMapping("/info")
public String getQuartzJob(String name, String group) {
String info = null;
try {
info = quartzSchedulerNew.getJobInfo(name, group);
} catch (SchedulerException e) {
e.printStackTrace();
}
return info;
}
@RequestMapping("/modify")
public boolean modifyQuartzJob(String name, String group, String time) {
boolean flag = true;
try {
flag = quartzSchedulerNew.modifyJob(name, group, time);
} catch (SchedulerException e) {
e.printStackTrace();
}
return flag;
}
@RequestMapping(value = "/pause")
public void pauseQuartzJob(String name, String group) {
try {
quartzSchedulerNew.pauseJob(name, group);
} catch (SchedulerException e) {
e.printStackTrace();
}
}
@RequestMapping(value = "/pauseAll")
public void pauseAllQuartzJob() {
try {
quartzSchedulerNew.pauseAllJob();
} catch (SchedulerException e) {
e.printStackTrace();
}
}
@RequestMapping(value="/resumeAll")
public void resume(){
try {
quartzSchedulerNew.resumeAllJob();
} catch (SchedulerException e) {
e.printStackTrace();
}
}
@RequestMapping(value = "/delete")
public void deleteJob(String name, String group) {
try {
quartzSchedulerNew.deleteJob(name, group);
} catch (SchedulerException e) {
e.printStackTrace();
}
}
}
解决springboot不能在quartz注入bean的问题
我们想在quartz中的job中做出一些其他操作,尤其是操作数据库的操作,但当我们注入service对象运行时,却发现出现问题,以下就是我们的解决方式:
JobFactory
import org.quartz.spi.TriggerFiredBundle;
import org.springframework.beans.factory.config.AutowireCapableBeanFactory;
import org.springframework.scheduling.quartz.AdaptableJobFactory;
import org.springframework.stereotype.Component;
@Component
public class JobFactory extends AdaptableJobFactory {
/**
* AutowireCapableBeanFactory接口是BeanFactory的子类
* 可以连接和填充那些生命周期不被Spring管理的已存在的bean实例
*/
private AutowireCapableBeanFactory factory;
public JobFactory(AutowireCapableBeanFactory factory) {
this.factory = factory;
}
/**
* 创建Job实例
*/
@Override
protected Object createJobInstance(TriggerFiredBundle bundle) throws Exception {
// 实例化对象
Object job = super.createJobInstance(bundle);
// 进行注入(Spring管理该Bean)
factory.autowireBean(job);
//返回对象
return job;
}
}
QuartzConfig
import org.quartz.Scheduler;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.quartz.SchedulerFactoryBean;
@Configuration
public class QuartzConfig {
private JobFactory jobFactory;
public QuartzConfig(JobFactory jobFactory){
this.jobFactory = jobFactory;
}
/**
* 配置SchedulerFactoryBean
* 将一个方法产生为Bean并交给Spring容器管理
*/
@Bean
public SchedulerFactoryBean schedulerFactoryBean() {
// Spring提供SchedulerFactoryBean为Scheduler提供配置信息,并被Spring容器管理其生命周期
SchedulerFactoryBean factory = new SchedulerFactoryBean();
// 设置自定义Job Factory,用于Spring管理Job bean
factory.setJobFactory(jobFactory);
return factory;
}
@Bean(name = "scheduler")
public Scheduler scheduler() {
return schedulerFactoryBean().getScheduler();
}
}
最后我们在配置文件里加入下面这句话
spring.main.allow-bean-definition-overriding=true