任务调度:Quartz

首先,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:定义任务数据,执行逻辑。如上面例子的提醒我今天是男朋友的生日、提醒我大姨妈快要来了、提醒我起来走走运动运动。

扫描二维码关注公众号,回复: 3669842 查看本文章

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")
    @ApiOperation(value = "启动", produces = MediaType.APPLICATION_JSON_VALUE)
    public JsonResponse<?> startup(@ApiParam("定时任务id") @RequestParam String id) {
        try {
            Timer timer = timerService.findById(id);
            if (null == timer) {
                return new JsonResponse<>(400, "没有对应记录【id=" + id + "】");
            }
            TriggerKey triggerKey = getTriggerKey(timer);
            CronTrigger trigger = (CronTrigger) scheduler.getTrigger(triggerKey);
            if (null == trigger) {// 不存在,创建一个
                JobKey jobKey = getJobKey(timer);
                JobDetail jobDetail = JobBuilder.newJob(QuartzJob.class).withIdentity(jobKey)
                        /* .usingJobData("data", job.getJobData()) */.build();
                jobDetail.getJobDataMap().put(QuartzJob.JOB_DATA_MAP, timer);
                CronScheduleBuilder scheduleBuilder = CronScheduleBuilder.cronSchedule(timer.getCron());
                trigger = TriggerBuilder.newTrigger().withDescription(timer.getTimerName()).withIdentity(triggerKey)
                        .withSchedule(scheduleBuilder).build();
                scheduler.scheduleJob(jobDetail, trigger);
            } else {// 已存在,那么更新相应的定时设置
                CronScheduleBuilder scheduleBuilder = CronScheduleBuilder.cronSchedule(timer.getCron());
                // 按新的cronExpression表达式重新构建trigger
                trigger = trigger.getTriggerBuilder().withIdentity(
                        triggerKey)/* .usingJobData("data", job.getJobData()) */
                        .withSchedule(scheduleBuilder).build();
                // 按新的trigger重新设置job执行
                scheduler.rescheduleJob(triggerKey, trigger);
            }
            return new JsonResponse<>(timer);
        } catch (SchedulerException e) {
            return new JsonResponse<>(400, "操作失败!原因:"+e.getMessage());
        } catch (Exception e) {
            e.printStackTrace();
            return new JsonResponse<>(500, e.getMessage());
        }
    }

    @PostMapping(value = "/shutdown")
    @ApiOperation(value = "关闭", produces = MediaType.APPLICATION_JSON_VALUE)
    public JsonResponse<?> shutdown(@ApiParam("定时任务id") @RequestParam String id) {
        try {
            Timer timer = timerService.findById(id);
            if (null == timer) {
                return new JsonResponse<>(400, "没有对应记录【id=" + id + "】");
            }
            JobKey jobKey = getJobKey(timer);
            scheduler.deleteJob(jobKey);
            return new JsonResponse<>(timer);
        } catch (SchedulerException e) {
            return new JsonResponse<>(400, "操作失败!原因:"+e.getMessage());
        } catch (Exception e) {
            e.printStackTrace();
            return new JsonResponse<>(500, e.getMessage());
        }
    }

    @PostMapping(value = "/pause")
    @ApiOperation(value = "暂停", produces = MediaType.APPLICATION_JSON_VALUE)
    public JsonResponse<?> pause(@ApiParam("定时任务id") @RequestParam String id) {
        try {
            Timer timer = timerService.findById(id);
            if (null == timer) {
                return new JsonResponse<>(400, "没有对应记录【id=" + id + "】");
            }
            JobKey jobKey = getJobKey(timer);
            scheduler.pauseJob(jobKey);
            return new JsonResponse<>(timer);
        } catch (SchedulerException e) {
            return new JsonResponse<>(400, "操作失败!原因:"+e.getMessage());
        } catch (Exception e) {
            e.printStackTrace();
            return new JsonResponse<>(500, e.getMessage());
        }
    }

    @PostMapping(value = "/resume")
    @ApiOperation(value = "恢复", produces = MediaType.APPLICATION_JSON_VALUE)
    public JsonResponse<?> resume(@ApiParam("定时任务id") @RequestParam String id) {
        try {
            Timer timer = timerService.findById(id);
            if (null == timer) {
                return new JsonResponse<>(400, "没有对应记录【id=" + id + "】");
            }
            JobKey jobKey = getJobKey(timer);
            scheduler.resumeJob(jobKey);
            return new JsonResponse<>(timer);
        } catch (SchedulerException e) {
            return new JsonResponse<>(400, "操作失败!原因:"+e.getMessage());
        } catch (Exception e) {
            e.printStackTrace();
            return new JsonResponse<>(500, e.getMessage());
        }
    }

    @PostMapping(value = "/runOnce")
    @ApiOperation(value = "立即运行一次", produces = MediaType.APPLICATION_JSON_VALUE)
    public JsonResponse<?> runOnce(@ApiParam("定时任务id") @RequestParam String id) {
        try {
            Timer timer = timerService.findById(id);
            if (null == timer) {
                return new JsonResponse<>(400, "没有对应记录【id=" + id + "】");
            }
            SimpleScheduleBuilder scheduleBuilder = SimpleScheduleBuilder.simpleSchedule().withRepeatCount(0);// 只执行1次,即重复0次
            SimpleTrigger trigger = TriggerBuilder.newTrigger().withSchedule(scheduleBuilder).build();
            JobDetail jobDetail = JobBuilder.newJob(QuartzJob.class).build();
            jobDetail.getJobDataMap().put(QuartzJob.JOB_DATA_MAP, timer);
            scheduler.scheduleJob(jobDetail, trigger);
            return new JsonResponse<>(timer);
        } catch (SchedulerException e) {
            return new JsonResponse<>(400, "操作失败!原因:"+e.getMessage());
        } catch (Exception e) {
            e.printStackTrace();
            return new JsonResponse<>(500, e.getMessage());
        }
    }

    private TriggerKey getTriggerKey(Timer timer) {
        return TriggerKey.triggerKey(timer.getTimerId());
    }

    private JobKey getJobKey(Timer timer) {
        return JobKey.jobKey(timer.getTimerId());
    }

@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;
    }
}

猜你喜欢

转载自blog.csdn.net/U2133048/article/details/82775747