引言最近项目中有这样一个业务,相信大家也经常遇到。就是用户通过前端设置了某年某月某日的定时任务,后台接收并且定时执行。这个定时可以通过前端UI改变,或者删除,所以后端也需要做三个事,1-添加定时任务,
引言
最近项目中有这样一个业务,相信大家也经常遇到。就是用户通过前端设置了某年某月某日的定时任务,后台接收并且定时执行。这个定时可以通过前端UI改变,或者删除,所以后端也需要做三个事,1-添加定时任务,2-修改定时任务时间,3-删除定时任务。
Spring的定时任务
Spring通过@Scheduled注解为定时任务,cron表达式里写执行的时机,确实能够定时执行某个方法,但是却没办法灵活的管理任务的添加,改变,丢弃。所以不满足我们的需求。
@Scheduled(cron="0/10 * * * * ? ") //每10秒执行一次
自定义org.quartz.Scheduler.Scheduler实现灵活定时任务管理
1. 建一个Scheduler的包装类,提供单例实例的获取
这里生成一个Scheduler的包装类,并且只返回自身的单例。并通过getScheduler()获取到Scheduler的实例,这里也保证他它是单例。
SchedulerController.java
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()); } // 单例模式 生成Scheduler private Scheduler getScheduler() { try { myScheduler = Optional.ofNullable(myScheduler).orElse(new StdSchedulerFactory().getScheduler()); } catch (SchedulerException e) { throw new RuntimeException(e); } return myScheduler; }}
2.新建任务注册到Scheduler并启动
通过addJob()方法添加任务,接收的是一个Job类的实现类。startScheduler()启动任务。其中添加任务分为几步。
- 生成一个JobDetail类的实例,封装你的任务细节。包含了一个JobKey描述任务名跟任务组。
- 生成一个Trigger触发器的实例,封装你的定时时间。包含了一个TriggerKey描述任务名跟任务组。
- 把JobDetail跟Trigger注册到你的Scheduler中。
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 { // 添加jobDetail跟trigger 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.java
@Datapublic 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"); }}
3.修改任务时间,删除任务
上面说了任务时间是封装到Trigger触发器的,所以修改任务的核心代码在于CronTriggerImpl#setCronExpression(),来重设时间,再通过Scheduler#rescheduleJob()来重置。
删除任务则是Scheduler#unscheduleJob()跟Scheduler#deleteJob()。
SchedulerController.java
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("triggerNotExist"); } return triggers.get(jobName);}private JobKey getJobByName(String jobName) { if (!jobs.containsKey(jobName)) { throw new RuntimeException("jobNotExist"); } return jobs.get(jobName);}
4.测试一下
先每隔一秒实行job,然后改为两秒,最后删除任务。
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");
总结
自定义定时任务比较复杂,但是学会了后能够灵活的处理定时任务。
.
- 0