基本原理:设置两次定时任务,一次定时任务专门用来查看apollo的配置是否修改。另一次则是项目需要执行的定时任务
【这样写的好处】
- 同一时间执行多个定时任务,
一个定时任务失败,不会导致其他定时任务阻塞
- 动态从apollo获取定时任务执行时间,
不需要每次更改定时时间都重新部署服务
- 定时任务比较少时,免去维护数据库的过程
废话不多说,直接上代码,走着
一、引入依赖
<!-- 引入quartz依赖-->
<dependency>
<groupId>org.quartz-scheduler</groupId>
<artifactId>quartz</artifactId>
</dependency>
<!-- 该依赖必加,里面有sping对schedule的支持 -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context-support</artifactId>
</dependency>
二、需要执行的定时任务
其中,reset()
方法动态从apollo
获取;method2()
的定时时间代码写死,不是动态的;
@Configuration
@Component
@EnableScheduling
public class TaskConfig {
public void reset(){ //需要执行的定时任务
//定时任务的业务代码XXXXXXXXXXXXXXXXXXXXXX
}
//当有第二个需要执行的定时任务
public void method2(){
}
}
三、Quartz配置类
@Configuration
public class QuartzConfigration {
@Bean(name = "jobDetail")
public MethodInvokingJobDetailFactoryBean detailFactoryBean(TaskConfig taskConfig){ //需要定时执行的任务
MethodInvokingJobDetailFactoryBean jobDetail = new MethodInvokingJobDetailFactoryBean();
/*
* 是否并发执行
* 例如每5s执行一次任务,但是当前任务还没有执行完,就已经过了5s了,
* 如果此处为true,则下一个任务会执行,如果此处为false,则下一个任务会等待上一个任务执行完后,再开始执行
*/
jobDetail.setConcurrent(false); //等待上一个任务执行完,再开始执行
jobDetail.setName("resetTask"); //设置任务的名字
jobDetail.setTargetObject(taskConfig); //为需要执行的实体类对应的对象(定时方法所在类的对象)
jobDetail.setTargetMethod("reset"); // 为需要执行的方法(需要执行的定时任务方法)
return jobDetail;
}
/**
* attention:
* Details:配置定时任务的触发器,也就是什么时候触发执行定时任务
* 注意!!!!入参JobDetail 对象 jobDetail需要和 上面注入的名称一致!!!!!
*/
@Bean(name = "jobTrigger")
public CronTriggerFactoryBean cronJobTrigger(JobDetail jobDetail){
CronTriggerFactoryBean trigger = new CronTriggerFactoryBean();
trigger.setJobDetail(jobDetail);
trigger.setCronExpression("0 0 0 * * ?"); //初始时的cron表达式
return trigger;
}
// 第二个定时任务的配置
@Bean(name = "jobDetail2")
public MethodInvokingJobDetailFactoryBean detailFactoryBean(TaskConfig taskConfig){ //需要定时执行的任务
MethodInvokingJobDetailFactoryBean jobDetail = new MethodInvokingJobDetailFactoryBean();
jobDetail.setConcurrent(false);
jobDetail.setName("task2");
jobDetail.setTargetObject(taskConfig);
jobDetail.setTargetMethod("method2");
return jobDetail;
}
/**
* attention:
* Details:配置定时任务的触发器,也就是什么时候触发执行定时任务
*/
@Bean(name = "jobTrigger2")
public CronTriggerFactoryBean cronJobTrigger(JobDetail jobDetail2){
CronTriggerFactoryBean trigger = new CronTriggerFactoryBean();
trigger.setJobDetail(jobDetail2);
trigger.setCronExpression("0 0 0 * * ?");
return trigger;
}
/**
*
* @param cronJobTrigger
* @return 定义quartz调度工厂
* 注意!!!!入参Trigger 对象 jobTrigger、jobTrigger2 要和 上面注入的触发器名称一致!!!!!
* 有几个任务,配置几个触发器,将需要执行的触发器注入
*/
@Bean(name = "scheduler")
public SchedulerFactoryBean schedulerFactory(Trigger jobTrigger,Trigger jobTrigger2){
SchedulerFactoryBean bean = new SchedulerFactoryBean();
// 用于quartz集群,QuartzScheduler 启动时更新己存在的Job
bean.setOverwriteExistingJobs(true);
// 延时启动,应用启动1秒后
bean.setStartupDelay(1);
// 注册触发器
bean.setTriggers(jobTrigger,jobTrigger2);
return bean;
}
}
四、获取定时任务动态执行时间
@Configuration
@EnableScheduling
@Component
public class ScheduleRefreshApollo {
@Resource(name = "jobDetail")
private JobDetail jobDetail;
@Resource(name = "jobTrigger")
private CronTrigger cronTrigger;
@Resource(name = "scheduler")
private Scheduler scheduler;
@Scheduled(fixedDelay = 60000) //每隔1分钟,获取apollo数据,决定是否重置定时任务
public void scheduleUpdateCronTrigger() throws SchedulerException {
CronTrigger trigger = (CronTrigger) scheduler.getTrigger(cronTrigger.getKey());
String currentCron = trigger.getCronExpression();//当前trigger使用的
String searchCron = SystemConfigValues.get("job.cron");//获取apollo配置的时间,这里是公司封装的方法,需要修改为自己的动态时间
System.out.println(">>>>>>>>>>currentCron>>>>>>>>>>>" + currentCron + ",searchCron>>>>>>>>>>>" + searchCron);
if (null != searchCron && null!=currentCron && !searchCron.equals(currentCron)){
// 表达式调度构建器
CronScheduleBuilder scheduleBuilder = CronScheduleBuilder.cronSchedule(searchCron);
// 按新的cronExpression表达式重新构建trigger
trigger = (CronTrigger)scheduler.getTrigger(cronTrigger.getKey());
trigger = trigger.getTriggerBuilder().withIdentity(cronTrigger.getKey()).withSchedule(scheduleBuilder).build();
// 按新的trigger重新设置job执行
scheduler.rescheduleJob(cronTrigger.getKey(),trigger);
currentCron = searchCron;
}
}
}