添加引用
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-quartz</artifactId>
</dependency>
QuartzFactory类:主要用于解决springboot quartz job 无法注入bean的问题。
package com.example.springboot;
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 QuartzFactory extends AdaptableJobFactory {
/**
* AutowireCapableBeanFactory接口是BeanFactory的子类
* 可以连接和填充那些生命周期不被Spring管理的已存在的bean实例
*/
private AutowireCapableBeanFactory factory;
public QuartzFactory(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类:主要用于解决springboot quartz job 无法注入bean的问题,需要配合QuartzFactory类。
package com.example.springboot;
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 QuartzFactory quartzFactory;
public QuartzConfig(QuartzFactory quartzFactory) {
this.quartzFactory = quartzFactory;
}
/**
* 配置SchedulerFactoryBean
* 将一个方法产生为Bean并交给Spring容器管理
*/
@Bean
public SchedulerFactoryBean schedulerFactoryBean() {
// Spring提供SchedulerFactoryBean为Scheduler提供配置信息,并被Spring容器管理其生命周期
SchedulerFactoryBean factory = new SchedulerFactoryBean();
// 设置自定义Job Factory,用于Spring管理Job bean
factory.setJobFactory(quartzFactory);
return factory;
}
@Bean(name = "scheduler")
public Scheduler scheduler() {
return schedulerFactoryBean().getScheduler();
}
}
QuartzService类:封装一些任务调度的东西,主要也用于测试注入job的bean对象。
package com.example.springboot;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.exception.ExceptionUtils;
import org.quartz.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.text.SimpleDateFormat;
import java.util.Date;
@Slf4j
@Service
public class QuartzService {
@Autowired
private Scheduler scheduler;
// 添加调度任务
public Boolean addScheduler(Integer id, String cron) throws Exception {
// 判断,如果因为意外将过期调度任务传递过来,进行排除
// ...
// 添加一个去重复的操作
if (scheduler.getJobDetail(JobKey.jobKey(id.toString())) != null) {
return Boolean.TRUE;
}
// 构建一个job
JobDetail jobDetail = JobBuilder
.newJob(QuartzJob.class)
.withIdentity(id.toString())
.usingJobData("param", id.toString())
.build();
// 构建一个trigger
CronTrigger trigger = TriggerBuilder.newTrigger()
.withIdentity(id.toString())
.withSchedule(CronScheduleBuilder.cronSchedule(cron))
.build();
// 构建一个scheduler
Date nextExecuteTime = scheduler.scheduleJob(jobDetail, trigger);
//开始执行
scheduler.start();
return Boolean.TRUE;
}
// 取消调度任务,并且清除缓存
public Boolean deleteJob(Integer id) {
Boolean result = Boolean.FALSE;
try {
// 删除job
result = scheduler.deleteJob(JobKey.jobKey(id.toString()));
} catch (Exception ex) {
// 记录个日志
log.error(String.format("%s-删除调度器出现异常:%s,堆栈信息:%s", id, ex.getMessage(), ExceptionUtils.getStackTrace(ex)));
}
return result;
}
// 查询调度任务
public Boolean query(Integer id) throws Exception {
JobDetail jobDetail = scheduler.getJobDetail(JobKey.jobKey(id.toString()));
if (jobDetail == null) {
return Boolean.FALSE;
} else {
return Boolean.TRUE;
}
}
// 得到cron的下一次执行时间
public String getNextExecuteTime(String cron) {
SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
// 验证cron的正确性
System.out.println(CronExpression.isValidExpression(cron));
if (CronExpression.isValidExpression(cron)) {
CronTrigger trigger = TriggerBuilder.newTrigger()
.withIdentity("default")
.withSchedule(CronScheduleBuilder.cronSchedule(cron))
.build();
// 获取到下一次执行时间
Date nextTime = trigger.getFireTimeAfter(trigger.getStartTime());
return df.format(nextTime);
} else {
return "表达式不合法";
}
}
}
QuartzJob类:就是job要执行的类,该类如果不做特殊处理,是无法将bean对象注入该类的。重点就是QuartzFactory和QuartzConfig两个类的添加,没有什么需要特别注意的东西。
package com.example.springboot;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.exception.ExceptionUtils;
import org.quartz.Job;
import org.quartz.JobDataMap;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
@Slf4j
@Component
public class QuartzJob implements Job {
// 正常情况下,这里是注入不进来的,故意写个来检验注入bean问题
@Autowired
private QuartzService quartzService;
@Override
public void execute(JobExecutionContext context) throws JobExecutionException {
try {
JobDataMap jobDataMap = context.getJobDetail().getJobDataMap();
// 获取参数
String param = jobDataMap.getString("param");
System.out.println(param + "——开始执行");
Thread.sleep(1000);
// 调用删除调度器的方法
Boolean result = quartzService.deleteJob(Integer.valueOf(param));
System.out.println(param + "——执行结束,取消调度任务结果:" + result);
} catch (Exception ex) {
log.error(String.format("执行调度器出现异常:%s,堆栈信息:%s", ex.getMessage(), ExceptionUtils.getStackTrace(ex)));
}
}
}
QuartzController类:测试类,用于调用任务的添加,删除和查询。
package com.example.springboot;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@Slf4j
@RestController
public class QuartzController {
@Autowired
private QuartzService quartzService;
@RequestMapping("/quartz/add/{id}")
private Boolean index(@PathVariable Integer id, @RequestBody String cron) throws Exception {
Boolean result = quartzService.addScheduler(id, cron);
return result;
}
@RequestMapping("/quartz/delete/{id}")
public Boolean cancel(@PathVariable Integer id) {
Boolean result = quartzService.deleteJob(id);
return result;
}
@RequestMapping("/quartz/query/{id}")
public Boolean query(@PathVariable Integer id) throws Exception {
Boolean result = quartzService.query(id);
return result;
}
}
注意:由于job类无法注入spring bean对象,因此需要添加QuartzFactory和QuartzConfig两个类,然后Scheduler调用方式,不是采用new,而是注入的方式,参见QuartzService中的Scheduler使用。
吐槽一下,网上代码都是各种copy,找点有用的找不到。就想找为什么job类无法注入,解决方案都找半天没有用,后来自己总结搞了下,其实就是添加两个类就可以了,很简单,非得贴一大坨代码,也没有说明解释。springboot quartz无法注入问题参见上述红字把。