springboot 整合quartz详解

本文主要是针对springboot 整合quartz 来说明,作为一个小白我总喜欢上网查找资料,然后希望找的东西能80%符合自己的需求,能直接拿来用的,但是很多时候网上的案例都是一个copy一个的,看的东西千篇一律,而且有些内容解释的也是寥寥数语,所以有时候也需要自己写点东西分享给大众,今天也是自己刚申请csdn ,取的笔名为:随笔发烧友,励志自己后面能多写文章,乐在分享。好了,进入正题吧!

Quartz

quartz是一个java编写的开源任务调度框架其主要调度元素有:

  • Trigger(触发器):触发任务任务执行的时间或规则。在任务调度Quartz中,Trigger主要的触发器有:SimpleTrigger,CalendarIntervelTrigger,DailyTimeIntervalTrigger,CronTrigger
  • Scheduler(任务调度器):Scheduler就是任务调度控制器,需要把JobDetail和Trigger注册到schedule中,才可以执行 ;Scheduler有两个重要组件:ThreadPool和JobStore。
  • Job(任务):是一个接口,其中只有一个execute方法。开发者只要实现接口中的execute方法即可。
  • JobDetail(任务细节):Quartz执行Job时,需要新建Job实例,但不能直接操作Job类,所以通过JobDetail获得Job的名称,描述信息。

先了解quartz四大要素,然后我们的目的就是组合四大要素,实现任务的创建,并启用/暂停/移除/更新操作

1、编写一个自己要实现的任务类,实现Job接口中的执行方法 execute

/**
 * 定时任务实现类
 */
@Configuration
@Component
@EnableScheduling
public class ScheduleTask1 implements Job {
 
    private static Logger logger = LoggerFactory.getLogger(ScheduleTask1.class);
 
    @Override
    public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException {
        try {
            System.out.print("任务执行1 :");
            System.out.println(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()));
 
        } catch (Exception e) {
            logger.error(e.getMessage());
        }
    }

2、构建任务细节

@Service
public class TaskService {

    @SuppressWarnings("unused")
    private final Logger logger = LoggerFactory.getLogger(this.getClass()); 

    @Autowired     
    private SchedulerFactoryBean schedulerFactoryBean;   

    @Autowired
    private QuartzJobRepository repository;

    /**    
     * 获取单个任务    
     * @param jobName    
     * @param jobGroup    
     * @return    
     * @throws SchedulerException    
     */    
    public QuartzJobBean getJob(String jobName,String jobGroup) throws SchedulerException {
        QuartzJobBean job = null;    
        Scheduler scheduler = getScheduler();
        TriggerKey triggerKey = TriggerKey.triggerKey(jobName, jobGroup);    
        CronTrigger trigger = (CronTrigger) scheduler.getTrigger(triggerKey);
        if (null != trigger) {
            job = createJob(jobName, jobGroup, scheduler, trigger);
        }

        return job;
    }

    private Scheduler getScheduler() {
        return schedulerFactoryBean.getScheduler();
    }

    private QuartzJobBean createJob(String jobName, String jobGroup, Scheduler scheduler, Trigger trigger)
            throws SchedulerException {
        QuartzJobBean job;
        job = new QuartzJobBean();
        job.setJobName(jobName);    
        job.setJobGroup(jobGroup);    
        job.setDescription("触发器:" + trigger.getKey()); 
        job.setNextTime(trigger.getNextFireTime());
        job.setPreviousTime(trigger.getPreviousFireTime());

        Trigger.TriggerState triggerState = scheduler.getTriggerState(trigger.getKey());
        job.setJobStatus(triggerState.name());

        if(trigger instanceof CronTrigger) {
            CronTrigger cronTrigger = (CronTrigger)trigger;
            String cronExpression = cronTrigger.getCronExpression();
            job.setCronExpression(cronExpression);
        }
        return job;
    }

    /**    
     * 获取所有任务    
     * @return    
     * @throws SchedulerException    
     */    
    public List<QuartzJobBean> getAllJobs() throws SchedulerException{   
        Scheduler scheduler = getScheduler();
        GroupMatcher<JobKey> matcher = GroupMatcher.anyJobGroup();
        Set<JobKey> jobKeys = scheduler.getJobKeys(matcher);
        List<QuartzJobBean> jobList = new ArrayList<QuartzJobBean>();
        List<? extends Trigger> triggers;
        QuartzJobBean job;
        for (JobKey jobKey : jobKeys) {
            triggers = scheduler.getTriggersOfJob(jobKey);
            for (Trigger trigger : triggers) {
                job = createJob(jobKey.getName(), jobKey.getGroup(), scheduler, trigger);
                jobList.add(job);
            }
        }

        return jobList;
    }

    /**    
     * 所有正在运行的job    
     *     
     * @return    
     * @throws SchedulerException    
     */    
    public List<QuartzJobBean> getRunningJob() throws SchedulerException {
        Scheduler scheduler = getScheduler();
        List<JobExecutionContext> executingJobs = scheduler.getCurrentlyExecutingJobs();
        List<QuartzJobBean> jobList = new ArrayList<QuartzJobBean>(executingJobs.size());
        QuartzJobBean job;
        JobDetail jobDetail;
        JobKey jobKey;

        for (JobExecutionContext executingJob : executingJobs) {
            jobDetail = executingJob.getJobDetail();
            jobKey = jobDetail.getKey();

            job = createJob(jobKey.getName(), jobKey.getGroup(), scheduler, executingJob.getTrigger());
            jobList.add(job);
        }

        return jobList;
    }

    /**    
     * 添加任务    
     *     
     * @param scheduleJob    
     * @throws SchedulerException    
     */    
    public boolean addJob(QuartzJobBean job) throws SchedulerException { 
        if(job == null || !QuartzJobBean.STATUS_RUNNING.equals(job.getJobStatus())) {
            return false;
        }

        String jobName = job.getJobName();
        String jobGroup = job.getJobGroup();
        if(!TaskUtils.isValidExpression(job.getCronExpression())) {
            logger.error("时间表达式错误("+jobName+","+jobGroup+"), "+job.getCronExpression());    
            return false;
        } else {
            Scheduler scheduler = getScheduler();
            // 任务名称和任务组设置规则:    // 名称:task_1 ..    // 组 :group_1 ..
            TriggerKey triggerKey = TriggerKey.triggerKey(jobName,  jobGroup);
            Trigger trigger = scheduler.getTrigger(triggerKey);
            // 不存在,创建一个       
            if (null == trigger) { 
                // 表达式调度构建器
                CronScheduleBuilder scheduleBuilder = CronScheduleBuilder.cronSchedule(job.getCronExpression());
                // 按新的表达式构建一个新的trigger
                trigger = TriggerBuilder.newTrigger().withIdentity(triggerKey)
                                                     .startAt(job.getStartTime()==null ? (new Date()) : job.getStartTime()) // 设置job不早于这个时间进行运行,和调用trigger的setStartTime方法效果一致
                                                     .withSchedule(scheduleBuilder).build();

                //是否允许并发执行
                JobDetail jobDetail = getJobDetail(job);
                // 将 job 信息存入数据库
                job.setStartTime(trigger.getStartTime());
                job.setNextTime(trigger.getNextFireTime());
                job.setPreviousTime(trigger.getPreviousFireTime());
                job = repository.save(job);
                jobDetail.getJobDataMap().put(getJobIdentity(job), job);

                scheduler.scheduleJob(jobDetail, trigger);

            } else { // trigger已存在,则更新相应的定时设置  
                // 更新 job 信息到数据库
                job.setStartTime(trigger.getStartTime());
                job.setNextTime(trigger.getNextFireTime());
                job.setPreviousTime(trigger.getPreviousFireTime());
                job = repository.save(job);
                getJobDetail(job).getJobDataMap().put(getJobIdentity(job), job);

                CronScheduleBuilder scheduleBuilder = CronScheduleBuilder.cronSchedule(job.getCronExpression());
                // 按新的表达式构建一个新的trigger
                trigger = TriggerBuilder.newTrigger().withIdentity(triggerKey)
                                                     .startAt(job.getStartTime()==null ? (new Date()) : job.getStartTime()) // 设置job不早于这个时间进行运行,和调用trigger的setStartTime方法效果一致
                                                     .withSchedule(scheduleBuilder).build();
                scheduler.rescheduleJob(triggerKey, trigger);
            }
        }
        return true;
    }

    private String getJobIdentity(QuartzJobBean job) {
        return "scheduleJob"+(job.getJobGroup() +"_"+job.getJobName());
    }

    private JobDetail getJobDetail(QuartzJobBean job) {
        Class<? extends Job> clazz = QuartzJobBean.CONCURRENT_IS.equals(job.isConcurrent()) 
                        ? QuartzJobFactory.class : QuartzJobFactoryDisallowConcurrentExecution.class;       
        JobDetail jobDetail = JobBuilder.newJob(clazz).withIdentity(job.getJobName(), job.getJobGroup()).build();
        return jobDetail;
    }

    /**    
     * 暂停任务    
     * @param job    
     * @return    
     */ 
    @Transactional
    public boolean pauseJob(QuartzJobBean job){    
        Scheduler scheduler = getScheduler();
        JobKey jobKey = JobKey.jobKey(job.getJobName(), job.getJobGroup());
        boolean result;
        try {
            scheduler.pauseJob(jobKey);

            // 更新任务状态到数据库
            job.setJobStatus(QuartzJobBean.STATUS_NOT_RUNNING);
            repository.modifyByStatus(job.getJobStatus(), job.getJobId());

            result = true;
        } catch (SchedulerException e) {
            result = false;
            e.printStackTrace();
        }
        return result;
    }

    /**    
     * 恢复任务    
     * @param job    
     * @return    
     */    
    @Transactional
    public boolean resumeJob(QuartzJobBean job){
        Scheduler scheduler = getScheduler();
        JobKey jobKey = JobKey.jobKey(job.getJobName(), job.getJobGroup());
        boolean result;
        try {
            logger.info("resume job : " + (job.getJobGroup() + "_" + job.getJobName()));
            TriggerKey triggerKey = TriggerKey.triggerKey(job.getJobName(), job.getJobGroup());
            // 表达式调度构建器
            CronScheduleBuilder scheduleBuilder = CronScheduleBuilder.cronSchedule(job.getCronExpression());
            Trigger trigger = TriggerBuilder.newTrigger().withIdentity(triggerKey)
                                            .startAt(job.getStartTime()==null ? (new Date()) : job.getStartTime()) // 设置job不早于这个时间进行运行,和调用trigger的setStartTime方法效果一致
                                            .withSchedule(scheduleBuilder).build();
            scheduler.rescheduleJob(triggerKey, trigger);
            scheduler.resumeJob(jobKey);

            // 更新任务状态到数据库
            job.setJobStatus(QuartzJobBean.STATUS_RUNNING);
            repository.modifyByStatus(job.getJobStatus(), job.getJobId());

            result = true;
        } catch (SchedulerException e) {
            result = false;
            e.printStackTrace();
        }
        return result;
    }

    /**    
     * 删除任务    
     */    
    @Transactional
    public boolean deleteJob(QuartzJobBean job){ 
        Scheduler scheduler = getScheduler();    
        JobKey jobKey = JobKey.jobKey(job.getJobName(), job.getJobGroup());    
        boolean result;
        try{    
            scheduler.deleteJob(jobKey);

            // 更新任务状态到数据库
            job.setJobStatus(QuartzJobBean.STATUS_DELETED);
            repository.modifyByStatus(job.getJobStatus(), job.getJobId());

            result = true;    
        } catch (SchedulerException e) {    
            result = false;
            e.printStackTrace();
        }    
        return result;    
    } 

    /**    
     * 立即执行一个任务    
     * @param scheduleJob    
     * @throws SchedulerException    
     */    
    public void startJob(QuartzJobBean scheduleJob) throws SchedulerException{
        Scheduler scheduler = getScheduler();  
        JobKey jobKey = JobKey.jobKey(scheduleJob.getJobName(), scheduleJob.getJobGroup());
        scheduler.triggerJob(jobKey);
    }

    /**    
     * 更新任务时间表达式    
     * @param job    
     * @throws SchedulerException    
     */    
    @Transactional
    public void updateCronExpression(QuartzJobBean job) throws SchedulerException {
        Scheduler scheduler = getScheduler();
        TriggerKey triggerKey = TriggerKey.triggerKey(job.getJobName(), job.getJobGroup());
        //获取trigger,即在spring配置文件中定义的 bean id="myTrigger"
        CronTrigger trigger = (CronTrigger) scheduler.getTrigger(triggerKey);
        //表达式调度构建器    
        CronScheduleBuilder scheduleBuilder = CronScheduleBuilder.cronSchedule(job.getCronExpression());
        //按新的cronExpression表达式重新构建trigger
        trigger = trigger.getTriggerBuilder().withIdentity(triggerKey).withSchedule(scheduleBuilder).build();
        //按新的trigger重新设置job执行
        scheduler.rescheduleJob(triggerKey, trigger);

        // 更新 job 信息到数据库
        job.setStartTime(trigger.getStartTime());
        job.setNextTime(trigger.getNextFireTime());
        job.setPreviousTime(trigger.getPreviousFireTime());
        job = repository.save(job);
        getJobDetail(job).getJobDataMap().put(getJobIdentity(job), job);
    }

    /**
     * 设置job的开始schedule时间
     * @param job
     * @throws SchedulerException
     */
    @Transactional
    public void updateStartTime(QuartzJobBean job) throws SchedulerException {
        Scheduler scheduler = getScheduler();
        TriggerKey triggerKey = TriggerKey.triggerKey(job.getJobName(), job.getJobGroup());
        //获取trigger,即在spring配置文件中定义的 bean id="myTrigger"
        CronTriggerImpl trigger = (CronTriggerImpl) scheduler.getTrigger(triggerKey);
        trigger.setStartTime(job.getStartTime());
        //按新的trigger重新设置job执行
        scheduler.rescheduleJob(triggerKey, trigger);

        // 更新 job 信息到数据库
        job.setStartTime(trigger.getStartTime());
        job.setNextTime(trigger.getNextFireTime());
        job.setPreviousTime(trigger.getPreviousFireTime());
        job = repository.save(job);
        getJobDetail(job).getJobDataMap().put(getJobIdentity(job), job);
    }

}

 服务启动时,读取数据库 job 信息,并进行 schedule

@Component
public class MyRunner implements CommandLineRunner {

    private Logger logger = LoggerFactory.getLogger(getClass());

    @Autowired     
    private TaskService taskService;

    @Autowired
    private QuartzJobService jobService;

    @Override
    public void run(String... args) throws Exception {
        // 可执行的任务列表        
        List<QuartzJobBean> taskList = jobService.findByJobStatus(QuartzJobBean.STATUS_RUNNING);     
        logger.info("初始化加载定时任务......");     
        for (QuartzJobBean job : taskList) {     
            try {
                taskService.addJob(job);     
            } catch (Exception e) {
                logger.error("add job error: " + job.getJobName() + " " + job.getJobGroup(), e);
            }
        }  
    }

}

猜你喜欢

转载自blog.csdn.net/weixin_42071874/article/details/82983542