1.问题如标题所说
使用springboot + quartz + cron表达式形式触发任务 + mysql jdbc 数据源
出现的问题是 重启服务时无法修改数据库已有任务的cron表达式也就是任务触发频率无法修改
2.解决方案
1.增加yml配置项
需要在yml 中添加如下语句即可
spring:
quartz:
overwrite-existing-jobs: true # 是否覆盖已有 Job 的配置
2. 增加处理类
在项目代码中增加如下类 本质类似都是通过修改bean的overwirteexistingjobs属性进行覆盖
看注解能知道是在bean配置后自动调用该方法修改 其实代码中如果想要手动修改定时任务应该通过scheduler.rescheduleJob就可以进行修改 但是需要获取到scheduler
@Configuration
@AutoConfigureAfter(QuartzAutoConfiguration.class)
public class QuartzSupportConfig{
@Autowired(required = false)
private List<Trigger> triggers ;
@Autowired
SchedulerFactoryBean schedulerFactoryBean;
@PostConstruct
public void quartzScheduler() throws SchedulerException {
schedulerFactoryBean.setOverwriteExistingJobs(true);
if (triggers != null){
Scheduler scheduler = schedulerFactoryBean.getScheduler();
for (Trigger trigger : triggers){
scheduler.rescheduleJob(trigger.getKey(),trigger);
}
}
}
}
3. 问题
1.尝试通过手动注入schedulerFactory 进行修改已有trigger 但是始终无法在启动服务时获取到数据库已有trigger
相关代码如下:(这个是错误代码哈 如果有大佬发现问题感谢指出)
@Configuration
public class UserSchedulerConfig {
//这里用了两个数据源 这个使用了分片 但是定时任务使用的铍铜任务
@Lazy
@Resource(name = "shardingDataSource")
DataSource shardingDataSource;
@Primary
@Bean
public DataSource defaultDataSource() {
return shardingDataSource;
}
// @Primary
@Bean
@QuartzDataSource
@ConfigurationProperties(prefix = "spring.quartz.properties.org.quartz.datasource")
public DataSource quartzDataSource(){
return new HikariDataSource();
}
//这里是关键点 =======================应该是这里没注入对
@Autowired
private JobFactory jobFactory;
@Bean(name="schedulerFactory")
public SchedulerFactoryBean schedulerFactoryBean() throws IOException {
SchedulerFactoryBean factory = new SchedulerFactoryBean();
//factory.setQuartzProperties(quartzProperties());
//这样当spring关闭时,会等待所有已经启动的quartz job结束后spring才能完全shutdown。
factory.setWaitForJobsToCompleteOnShutdown(true);
//这里是关键点 =======================应该是这里没注入对
factory.setJobFactory(jobFactory);
factory.setDataSource(quartzDataSource());
//延长启动
factory.setStartupDelay(1);
//用于quartz集群,QuartzScheduler 启动时更新己存在的Job 这里是关键点1 但是没拿到
//factory.setOverwriteExistingJobs(true);
return factory;
}
//这个监听器可以监听到工程的启动,在工程停止再启动时可以让已有的定时任务继续进行。
@Bean
public QuartzInitializerListener executorListener() {
return new QuartzInitializerListener();
}
//通过SchedulerFactoryBean获取Scheduler的实例
@Bean(name="scheduler")
public Scheduler scheduler() throws IOException {
return schedulerFactoryBean().getScheduler();
}
}
之后是 jobFactory注入那块
//=========这段代码打断点始终没进去 不知道为啥没执行
@Component
public class JobFactory extends AdaptableJobFactory {
@Autowired
private AutowireCapableBeanFactory capableBeanFactory;
@Override
protected Object createJobInstance(final TriggerFiredBundle bundle) throws Exception {
// 调用父类的方法
Object jobInstance = super.createJobInstance(bundle);
// 进行注入
capableBeanFactory.autowireBean(jobInstance);
return jobInstance;
}
}
之后是 任务配置类
@Configuration
public class QuartzConfig {
private final String cron="0 0/1 * * * ? ";
private final String jobName="cashOutJob";
//这里注入scheduler 任务就是bean工厂生成的类
@Autowired
private Scheduler scheduler;
@Bean
public JobDetail cashOutJob() {
return JobBuilder.newJob(CashOutJob.class).withIdentity(jobName).storeDurably().build();
}
@Bean
public Trigger cashOutJobTrigger() {
try {
TriggerKey triggerKey = TriggerKey.triggerKey(jobName);
//这里 原有思路就是看scheduler中是否有这个任务 如果有就更新 如果没有就创建新的
CronTrigger trigger = (CronTrigger)scheduler.getTrigger(triggerKey);
if(Objects.nonNull(trigger)){
String oldTime = trigger.getCronExpression();
if (!oldTime.equalsIgnoreCase(cron)) {
// 触发器
TriggerBuilder<Trigger> triggerBuilder = TriggerBuilder.newTrigger();
// 触发器名,触发器组
triggerBuilder.withIdentity(jobName, null);
triggerBuilder.startNow();
// 触发器时间设定
triggerBuilder.withSchedule(CronScheduleBuilder.cronSchedule(cron));
// 创建Trigger对象
trigger = (CronTrigger) triggerBuilder.build();
// 方式一 :修改一个任务的触发时间
scheduler.rescheduleJob(triggerKey, trigger);
}
return trigger;
}else{
//cron方式,每隔1min执行一次 这里的build方法如果没有scheduler会默认生成
return TriggerBuilder.newTrigger().forJob(cashOutJob())
.withIdentity("cashOutJob")
.withSchedule(CronScheduleBuilder.cronSchedule("* 0/1 * * * ? "))
.build();
}
} catch (SchedulerException e) {
e.printStackTrace();
return null;
}
}
}
2.quartz官网文档看着好难受 想找配置相关的发现没有yml配置形式 如果有合适的链接欢迎在评论区补充
3. quartz学的不够深入 可能有理解错误的地方
4. 参考资料
官方配置相关文档
SpringBoot整合任务调度框架Quartz及持久化配置
springBoot2.x设置quartz的overwriteExistingJobs参数
记一次Quartz重复调度(任务重复执行)的问题排查
spring-boot-2.0.3之quartz集成,不是你想的那样哦!
SpringBoot2.0整合Quartz定时任务(持久化到数据库,更为简单的方式)