最近项目中有这样一个业务,相信你们也常常遇到。就是用户经过前端设置了某年某月某日的定时任务,后台接收而且定时执行。这个定时能够经过前端UI改变,或者删除,因此后端也须要作三个事,1-添加定时任务,2-修改定时任务时间,3-删除定时任务。
前端
Spring经过@Scheduled注解为定时任务,cron表达式里写执行的时机,确实可以定时执行某个方法,可是却没办法灵活的管理任务的添加,改变,丢弃。因此不知足咱们的需求。java
@Scheduled(cron="0/10 * * * * ? ") //每10秒执行一次
复制代码
这里生成一个Scheduler的包装类,而且只返回自身的单例。并经过getScheduler()获取到Scheduler的实例,这里也保证他它是单例。后端
SchedulerController.javabash
public class SchedulerController {
private static SchedulerController own;
private Scheduler myScheduler;
HashMap<String, TriggerKey> triggers = new HashMap<String, TriggerKey>();
HashMap<String, JobKey> jobs = new HashMap<String, JobKey>();
private SchedulerController() {
}
// 单例模式
public static SchedulerController getInstance() {
return own = Optional.ofNullable(own).orElse(new SchedulerController());
}
private Scheduler getScheduler() {
try {
myScheduler = Optional.ofNullable(myScheduler).orElse(new StdSchedulerFactory().getScheduler());
} catch (SchedulerException e) {
throw new RuntimeException(e);
}
return myScheduler;
}
}
复制代码
经过addJob()方法添加任务,接收的是一个Job类的实现类。startScheduler()启动任务。其中添加任务分为几步。ide
SchedulerController.java测试
public Scheduler addJob(ScheduleJob job, String cron) {
Scheduler s = getScheduler();
// jobDetail生成
JobKey jobKey = new JobKey(job.getJobName(), job.getJobGroup());
jobs.put(job.getJobName(), jobKey);
JobDetail jobDetail = JobBuilder.newJob(job.getClass()).withIdentity(jobKey).build();
// trigger生成
TriggerKey triggerKey = new TriggerKey(job.getJobName(), job.getTriggerGroup());
triggers.put(job.getJobName(), triggerKey);
Trigger trigger = TriggerBuilder.newTrigger().withIdentity(triggerKey)
.withSchedule(CronScheduleBuilder.cronSchedule(cron)).build();
try {
s.scheduleJob(jobDetail, trigger);
} catch (SchedulerException e) {
throw new RuntimeException(e);
}
return s;
}
public void startScheduler() {
try {
if (myScheduler != null && !myScheduler.isShutdown()) {
myScheduler.start();
}
} catch (SchedulerException e) {
throw new RuntimeException(e);
}
}
复制代码
ScheduleJob.javaui
@Data
public class ScheduleJob implements Job {
private String jobName;
private String jobGroup;
private String triggerGroup;
public ScheduleJob() {
}
public ScheduleJob(String jobName) {
this.jobName = jobName;
}
@Override
public void execute(JobExecutionContext context) throws JobExecutionException {
// 实际执行内容
System.out.println("test");
}
}
复制代码
上面说了任务时间是封装到Trigger触发器总的,因此修改任务的核心代码在于CronTriggerImpl#setCronExpression(),来重设时间,再经过Scheduler#rescheduleJob()来重置。
删除任务则是Scheduler#unscheduleJob()跟Scheduler#deleteJob()。this
SchedulerController.javaspa
public void modifyJobTime(String jobName, String cronExpression) {
try {
if (myScheduler == null) {
return;
}
TriggerKey triggerKey = getTriggerKeyByName(jobName);
CronTriggerImpl trigger = (CronTriggerImpl) myScheduler.getTrigger(triggerKey);
if (trigger == null) {
return;
}
String oldTime = trigger.getCronExpression();
if (!oldTime.equalsIgnoreCase(cronExpression)) {
try {
trigger.setCronExpression(cronExpression);
} catch (ParseException e) {
throw new RuntimeException(e);
}
myScheduler.rescheduleJob(triggerKey, trigger);
}
} catch (SchedulerException e) {
throw new RuntimeException(e);
}
}
public void removeJob(String jobName) {
try {
myScheduler.pauseTrigger(getTriggerKeyByName(jobName));
myScheduler.unscheduleJob(getTriggerKeyByName(jobName));
myScheduler.deleteJob(getJobByName(jobName));
} catch (SchedulerException e) {
throw new RuntimeException(e);
}
}
private TriggerKey getTriggerKeyByName(String jobName) {
if (!triggers.containsKey(jobName)) {
throw new RuntimeException(msg.getMessage("triggerNotExist", new String[] { jobName }, null));
}
return triggers.get(jobName);
}
private JobKey getJobByName(String jobName) {
if (!jobs.containsKey(jobName)) {
throw new RuntimeException(msg.getMessage("jobNotExist", new String[] { jobName }, null));
}
return jobs.get(jobName);
}
复制代码
先每隔一秒实行job,而后改成两秒,最后删除任务。code
SchedulerController sc = SchedulerController.getInstance();
sc.addJob(new ScheduleJob("Test"), "*/1 * * * * ?");
sc.startScheduler();
try {
Thread.sleep(1000 * 5);
} catch (InterruptedException e) {
e.printStackTrace();
}
sc.modifyJobTime("Test", "*/2 * * * * ?");
sc.removeJob("Test");
复制代码
自定义定时任务比较复杂,可是学会了后可以灵活的处理定时任务。