问题描述
我们一般在使用定时框架的时候需要动态的控制定时任务的执行时间间隔, 平常我们都是使用cron表达式来实现, 但是如果我们的得到的参数是具体的秒数或者是分钟亦或者是小时, 如果是整数使用cron还可以, 当然cron是不允许出现60分钟执行一次的, 只能是1小时, 准确来说分钟不能超过59分钟否则会报错, 如果不是整数, 那么使用cron表达式会出现时间精度的丢失, 比如说我要一个半小时执行一次, 我通过时间转换的cron表达式, 可能只会每小时的30钟执行, (也可能是方法不对), 基于以上问题的出现, 网上找到一种办法, 如果参数是时间的话, 小时也好, 几十分钟也罢, 我们可以将其转换为秒数, 让它按照指定间隔的秒数去执行.
代码示例
pom.xml
<dependencies>
<!-- 引入quartz依赖 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-quartz</artifactId>
<version>2.3.12.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
<version>2.3.12.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<version>2.3.12.RELEASE</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.22</version>
</dependency>
</dependencies>
添加配置类
QuartzConfiguration
import org.quartz.Scheduler;
import org.quartz.ee.servlet.QuartzInitializerListener;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.quartz.SchedulerFactoryBeanCustomizer;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.quartz.AdaptableJobFactory;
import org.springframework.scheduling.quartz.SchedulerFactoryBean;
/**
* quartz配置类
*/
@Configuration
public class QuartzConfiguration extends AdaptableJobFactory implements SchedulerFactoryBeanCustomizer {
//初始化quartz监听器
@Bean
public QuartzInitializerListener quartzInitializerListener(){
return new QuartzInitializerListener();
}
//通过调度器工厂实例化调度器
@Bean
public Scheduler scheduler(){
return schedulerFactoryBean().getScheduler();
}
//并行
@Override
public void customize(SchedulerFactoryBean schedulerFactoryBean) {
schedulerFactoryBean.setStartupDelay(2);
schedulerFactoryBean.setAutoStartup(true);
schedulerFactoryBean.setOverwriteExistingJobs(true);
}
@Autowired
public JobFactory jobFactory;
/**
* 方法名:
* 功能:定义quartz调度工厂
*/
@Bean
public SchedulerFactoryBean schedulerFactoryBean(){
// 修改之后方可解决调用service空指针问题
SchedulerFactoryBean factoryBean = new SchedulerFactoryBean();
factoryBean.setJobFactory(jobFactory);
//是否覆盖之前的定时任务
factoryBean.setOverwriteExistingJobs(true);
// 延时启动(秒)
factoryBean.setStartupDelay(0);
System.out.println("scheduler 初始化成功!");
return factoryBean;
}
}
JobFactory
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.Service;
/***
* 解决调用 service 空指针
*/
@Service("jobFactory")
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;
}
}
添加控制器
import com.gsz.quartz.task.QuartzTask;
import org.quartz.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
/**
* @Project: hyfxiot
* explain: 控制定时任务的添加和重置.
*/
@Component
public class ScheduledManage {
// 调度器对象
@Autowired
private Scheduler scheduler;
/**
* 添加定时任务
*
* @param jName 工作明细
* @param triggerName 触发器名称
* @param seconds 执行间隔秒数
*/
public void addJob(String jName, String triggerName, int seconds) {
try {
//构建JobDetail工作明细 //test.testJob
JobDetail jobDetail = JobBuilder.newJob(QuartzTask.class).withIdentity(jName).build();
//构建Trigger触发器
Trigger trigger = TriggerBuilder.newTrigger()
.withIdentity(triggerName)
.startNow()
.withSchedule(SimpleScheduleBuilder.simpleSchedule()
.withIntervalInSeconds(seconds)
.repeatForever())
.build();
//启用调度器 来执行工作
scheduler.start();
scheduler.scheduleJob(jobDetail, trigger);
} catch (Exception e) {
System.out.println("创建定时任务失败了," + e);
}
}
/**
* 重置任务的cron规则
* @param triggerName 触发器名称 (需要跟添加时设置的触发器名称一致)
* @param seconds 定时规则 秒数
*/
public void rescheduleJob(String triggerName,int seconds) {
try {
//创建触发器的名字
// TriggerKey triggerKey = TriggerKey.triggerKey(tName, tGroup);
// 只有触发器名 没有分组.
TriggerKey triggerKey = TriggerKey.triggerKey(triggerName);
// 使用 SimpleScheduleBuilder
Trigger trigger = TriggerBuilder.newTrigger()
.withIdentity(triggerKey)
.startNow()
.withSchedule(SimpleScheduleBuilder.simpleSchedule()
.withIntervalInSeconds(seconds)
.repeatForever())
.build();
//按照新的trigger来执行job工作 重启触发器
scheduler.rescheduleJob(triggerKey, trigger);
} catch (SchedulerException e) {
e.printStackTrace();
}
}
}
controller
import com.gsz.quartz.config.ScheduledManage;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;
import java.util.Objects;
/**
* @Author gsz
* @Project: quartz-demo02
* @Date 2023/8/14 上午 9:53
* explain:
*/
@RestController
public class QuartzController {
// 任务控制器
@Autowired
private ScheduledManage scheduledManage;
/**
* 设置定时任务
* @param seconds 间隔时间 /s
*/
@GetMapping("/setTask/{seconds}")
public String setTask(@PathVariable("seconds") Integer seconds){
if (Objects.isNull(seconds) || seconds <= 0) return "seconds不合法!";
// 添加定时任务
scheduledManage.addJob("quartzTask","testTrigger",seconds);
return "设置任务成功!";
}
/**
* 重置定时任务
* @param seconds 秒数
*/
@GetMapping("/updateTask/{seconds}")
public String updateTask(@PathVariable("seconds") Integer seconds){
if (Objects.isNull(seconds) || seconds <= 0) return "seconds不合法!";
// 重置任务
scheduledManage.rescheduleJob("testTrigger",seconds);
return "任务重置成功!";
}
}