首先,Quartz是什么:
先看看我们生活中的例子:
每月的2月21号提醒我今天是男朋友的生日;
每月的17号提醒我大姨妈快要来了;
每隔一小时提醒我起来走走运动运动;
就是在某一个有规律的时间点干某件事。并且时间的触发的条件可以非常复杂(比如每月最后一个工作日的17:50),复杂到需要一个专门的框架来干这个事。 Quartz就是来干这样的事,你给它一个触发条件的定义,它负责到了时间点,触发相应的Job起来干活。
来一个简单的例子:
public class QuartzTest { public static void main(String[] args) { try { //创建scheduler Scheduler scheduler = StdSchedulerFactory.getDefaultScheduler(); //定义一个Trigger Trigger trigger = newTrigger().withIdentity("trigger1", "group1") //定义name/group .startNow()//一旦加入scheduler,立即生效 .withSchedule(simpleSchedule() //使用SimpleTrigger .withIntervalInSeconds(1) //每隔一秒执行一次 .repeatForever()) //一直执行,奔腾到老不停歇 .build(); //定义一个JobDetail JobDetail job = newJob(HelloQuartz.class) //定义Job类为HelloQuartz类,这是真正的执行逻辑所在 .withIdentity("job1", "group1") //定义name/group 确定唯一性 .usingJobData("name", "quartz") //定义属性 .build(); //加入这个调度 scheduler.scheduleJob(job, trigger); //启动之 scheduler.start(); //运行一段时间后关闭 Thread.sleep(10000); scheduler.shutdown(true); } catch (Exception e) { e.printStackTrace(); } } } |
public class HelloQuartz implements Job { public void execute(JobExecutionContext context) throws JobExecutionException { JobDetail detail = context.getJobDetail(); String name = detail.getJobDataMap().getString("name"); System.out.println("say happy birthday to " + name + " at " + new Date()); } } |
通过这个例子,我们看到这个任务主要有三个要素:
Scheduler:调度器。所有的调度都有它控制。也就是上面3条生活例子由他他进行调度。
Trigger :定义触发的条件。如上面的例子中每月的2月21号、每月的17号、每隔一小时是由它定义。
JobDetail & Job:定义任务数据,执行逻辑。如上面例子的提醒我今天是男朋友的生日、提醒我大姨妈快要来了、提醒我起来走走运动运动。
Trigger实现类:
SimpleTrigger:指定从某一个时间开始,以一定的时间间隔(单位是毫秒)执行的任务。它适合的任务类似于:9:00 开始,每隔1小时,执行一次。
simpleSchedule() .withIntervalInMinutes(1) //每分钟执行一次 .withRepeatCount(10) //次数为10次 .build(); |
CalendarIntervalTrigger:类似于SimpleTrigger,指定从某一个时间开始,以一定的时间间隔执行的任务。 但是不同的是SimpleTrigger指定的时间间隔为毫秒,没办法指定每隔一个月执行一次(每月的时间间隔不是固定值),而CalendarIntervalTrigger支持的间隔单位有秒,分钟,小时,天,月,年,星期。它适合的任务类似于:9:00 开始执行,并且以后每周 9:00 执行一次
calendarIntervalSchedule() .withIntervalInDays(1) //每天执行一次 .build(); calendarIntervalSchedule() .withIntervalInWeeks(1) //每周执行一次 .build(); |
DailyTimeIntervalTrigger:指定每天的某个时间段内,以一定的时间间隔执行任务。并且它可以支持指定星期。它适合的任务类似于:指定每天9:00 至 18:00 ,每隔70秒执行一次,并且只要周一至周五执行。
dailyTimeIntervalSchedule() .startingDailyAt(TimeOfDay.hourAndMinuteOfDay(9, 0)) //第天9:00开始 .endingDailyAt(TimeOfDay.hourAndMinuteOfDay(16, 0)) //16:00 结束 .onDaysOfTheWeek(MONDAY,TUESDAY,WEDNESDAY,THURSDAY,FRIDAY) //周一至周五执行 .withIntervalInHours(1) //每间隔1小时执行一次 .withRepeatCount(100) //最多重复100次(实际执行100+1次) .build(); dailyTimeIntervalSchedule() .startingDailyAt(TimeOfDay.hourAndMinuteOfDay(9, 0)) //第天9:00开始 .endingDailyAfterCount(10) //每天执行10次,这个方法实际上根据 startTimeOfDay+interval*count 算出 endTimeOfDay .onDaysOfTheWeek(MONDAY,TUESDAY,WEDNESDAY,THURSDAY,FRIDAY) //周一至周五执行 .withIntervalInHours(1) //每间隔1小时执行一次 .build(); |
CronTrigger:适合于更复杂的任务,它支持类型于Linux Cron的语法(并且更强大)。基本上它覆盖了以上三个Trigger的绝大部分能力(但不是全部)—— 当然,也更难理解。它适合的任务类似于:每天0:00,9:00,18:00各执行一次。
cronSchedule("0 0/2 8-17 * * ?") // 每天8:00-17:00,每隔2分钟执行一次 .build(); cronSchedule("0 30 9 ? * MON") // 每周一,9:30执行一次 .build(); weeklyOnDayAndHourAndMinute(MONDAY,9, 30) //等同于 0 30 9 ? * MON .build(); |
一个实例例子:
@PostMapping(value = "/startup") @PostMapping(value = "/shutdown") @PostMapping(value = "/pause") @PostMapping(value = "/resume") @PostMapping(value = "/runOnce") private TriggerKey getTriggerKey(Timer timer) { private JobKey getJobKey(Timer timer) { |
@DisallowConcurrentExecution// 同一个JobDetail不可并发执行 public class QuartzJob implements Job { public final Logger log = Logger.getLogger(this.getClass()); public static final String JOB_DATA_MAP = "gxmisJobDataMap"; @Autowired PoolingHttpClientConnectionManager cm; @Override public void execute(JobExecutionContext context) throws JobExecutionException { Timer timer = (Timer) context.getMergedJobDataMap().get(JOB_DATA_MAP); if(null == timer){ JobKey jobKey = context.getTrigger().getJobKey(); log.warn("定时任务【"+jobKey.getName()+"】缺少任务信息,将停止执行!"); try { context.getScheduler().deleteJob(jobKey); } catch (SchedulerException e) { log.error(e.getMessage()); } }else{ String url = timer.getServiceUrl(); if(CommonUtil.isEmtpy(url)){ // 什么也不做 }else{ url = formatUrl(url); HttpClient httpClient = HttpClients.custom().setConnectionManager(cm).build(); HttpGet post = new HttpGet(url); try { HttpResponse response = httpClient.execute(post); if(200 == response.getStatusLine().getStatusCode()){ // TODO 确定返回内容 System.out.println(CommonUtil.read(response.getEntity().getContent())); }else{ log.warn("123"); } } catch (IOException e) { log.warn(e.getMessage()); } } } } private String formatUrl(String url){ if(!url.startsWith("http://")){ url = "http://" + url; } return url; } } |