Quartz项目实践总结

Quartz介绍

Quartz是一个开源的任务调度系统,在实际的项目开发中需要很多调度任务来完成业务。为在项目更好应用,调试我们需要了解它主要结构,及特征。

运行特征

  • 很容易集成到应用程序中,spring有很好支持。
  • 支持各种cronExpression表达式定制触发器。
  • 可以将任务持久化到数据库,并支持集群。

主要对象

  1. Job表示一个工作,要执行的具体内容。此接口中只有一个方法
    void execute(JobExecutionContext context)
  2. JobDetail JobDetail表示一个具体的可执行的调度程序,Job是这个可执行程调度程序所要执行的内容,另外JobDetail还包含了这个任务调度的方案和策略。
  3. Trigger代表一个调度参数的配置,什么时候去调。
  4. Scheduler代表一个调度容器,一个调度容器中可以注册多个JobDetail和Trigger。当Trigger与JobDetail组合,就可以被Scheduler容器调度了。

通过如下代码例子来理解它们关系(quartz-2.2.1.jar):


public class quartzTest {



  public static void main(String[] args) {
    // TODO Auto-generated method stub

    try {
      // 3、创建Scheduler对象,并配置JobDetail和Trigger对象
      DirectSchedulerFactory schedulerFactory = DirectSchedulerFactory.getInstance();
      schedulerFactory.createVolatileScheduler(2);
      Scheduler scheduler = schedulerFactory.getScheduler();


      buildScheduler(scheduler);
      // 开启容器
      scheduler.start();
      // 查询容器中job
      showJobTask(scheduler);

    } catch (Exception e) {
      e.printStackTrace();
    }


  }

  public static void showJobTask(Scheduler scheduler) throws SchedulerException {
    List<String> jobGroupNames = scheduler.getJobGroupNames();

    for (String jobGroupName : jobGroupNames) {
      // scheduler.get
      Set<JobKey> jobKeys = scheduler.getJobKeys(GroupMatcher.jobGroupEquals(jobGroupName));
      for (JobKey jobKey : jobKeys) {
        JobDetail JobDetail = scheduler.getJobDetail(jobKey);
        System.out.println(JobDetail.getDescription() + "cccc" + jobKeys.toString());
      }
    }

  }


  public static void buildScheduler(Scheduler scheduler) throws SchedulerException {
    // 创建一个JobDetail
    JobDetail jobDetail = new JobDetailImpl("andreTaskName", "group1", TestTask.class);
    // 创建一个Trigger触发器
    SimpleTriggerImpl trigger = new SimpleTriggerImpl();
    trigger.setJobGroup("jobGroup");
    trigger.setName("trigger_one");
    trigger.setStartTime(new Date());
    // trigger.setEndTime(endTime);

    // 设置重复间隔时间 2s
    trigger.setRepeatInterval(2000L);
    trigger.setRepeatCount(3);
    // 添加到相应的scheduler容器中
    scheduler.scheduleJob(jobDetail, trigger);
  }

  /**
   * 具体job任务
   * 
   * @author my
   * @Date 2016年7月14日 下午3:47:57
   */
  public static class TestTask implements Job {

    @Override
    public void execute(JobExecutionContext context) throws JobExecutionException {
      // TODO Auto-generated method stub
      System.out.println("System executing something." + new Date());
    }

  }

}

总结

  1. scheduler是一个计划调度器容器(总部),容器里面可以盛放众多的JobDetail和trigger,当容器启动后,里面的每个JobDetail都会根据trigger按部就班自动去执行。
  2. JobDetail是一个可执行的工作,它本身可能是有状态的。对应数据表qrtz_job_details
  3. Trigger代表一个调度参数的配置,什么时候去调。qrtz_cron_triggers(主要cron表达式信息),qrtz_triggers(存储了prev_fire_time,trigger_state,next_fire_time等触发要素).
  4. scheduler是个容器,容器中有一个线程池,用来并行调度执行每个作业,这样可以提高容器效率。
  5. 清理某任务sql顺序:
----删除顺序应该这样,只有对cron_expression ,zone_id表达式记录。
DELETE FROM   qrtz_cron_triggers WHERE trigger_name="snapshotAnalyzeSchedulerTriggerBean2";
DELETE FROM qrtz_triggers WHERE trigger_name="snapshotAnalyzeSchedulerTriggerBean2";

--只描述了具体job
DELETE FROM qrtz_job_details  WHERE job_name="snapshotAnalyzeSchedulerJobDetail";

集群原理

一个 Quartz 集群中的每个节点是一个独立的 Quartz 应用,它又管理着其他的节点。意思是你必须对每个节点分别启动或停止。不像许多应用服务器的集群,独立的 Quartz 节点并不与另一其的节点或是管理节点通信。Quartz 应用是通过数据库表来感知到另一应用的。

图:表示了每个节点直接与数据库通信,若离开数据库将对其他节点一无所知

image

动态修改job

Quartz支持在scheduler.start();后动态addJob,ModifyJobTime,removeJob,pauseJob(停止任务),executeJob(立即执行任务)等。大家可以通过阅读代码来理解。

package com.calm.b.common.quartz;

import javax.annotation.Resource;

import org.quartz.CronTrigger;
import org.quartz.JobDataMap;
import org.quartz.JobKey;
import org.quartz.Scheduler;
import org.quartz.SchedulerFactory;
import org.quartz.impl.StdScheduler;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;


/**
 * 定时任务调试引擎,负责完成定时任务的执行、启动、停止。。。
 */
@Service("scheduleJobEngine")
public class ScheduleJobEngine {
  protected static Logger log = LoggerFactory.getLogger(ScheduleJobEngine.class);

  private static SchedulerFactory schedulerFactory = null;
  private static String JOB_GROUP_NAME = "DEFAULT";
  private static String TRIGGER_GROUP_NAME = "TRIGGERGROUP_NAME";

  /**
   * 注入的spring Scheduler容器bean
   */
  @Resource
  private StdScheduler quartzScheduler;

  /**
   * 增加任务
   * 
   * @param jobName
   * @param jobClass
   * @param expression
   */
  public static void addJob(String jobName, String jobClass, String expression) {
    addJob(jobName, JOB_GROUP_NAME, jobName, TRIGGER_GROUP_NAME, jobClass, expression);
  }

  public static void addJob(String jobName, String jobGroupName, String triggerName, String triggerGroupName,
      String jobClass, String expression) {
    log.debug("addJob:" + jobName);
    try {
      Scheduler scheduler = schedulerFactory.getScheduler();
      // JobDetail jobDetail = new JobDetail(jobName, jobGroupName, Class.forName(jobClass));//
      // 任务名,任务组,任务执行类
      // // 触发器
      // CronTrigger trigger = new CronTrigger(triggerName, triggerGroupName);// 触发器名,触发器组
      // trigger.setCronExpression(expression);// 触发器时间设定
      // scheduler.scheduleJob(jobDetail, trigger);
      // 启动
      if (!scheduler.isShutdown()) {
        scheduler.start();
      }
    } catch (Exception e) {
      log.error(e.getMessage(), e);

    }
  }

  /**
   * 修改任务执行时间
   * 
   * @param triggerName
   * @param expression
   */
  public static void modifyJobTime(String triggerName, String expression) {
    modifyJobTime(triggerName, TRIGGER_GROUP_NAME, expression);
  }

  public static void modifyJobTime(String triggerName, String triggerGroupName, String expression) {
    log.debug("modifyJobTime:" + triggerName);
    try {
      Scheduler scheduler = schedulerFactory.getScheduler();
      CronTrigger trigger = null;
      // = (CronTrigger) scheduler.getTrigger(triggerName, triggerGroupName);
      if (trigger == null) {
        return;
      }
      String oldTime = trigger.getCronExpression();
      if (!oldTime.equalsIgnoreCase(expression)) {
        CronTrigger ct = (CronTrigger) trigger;
        // 修改时间
        // ct.setCronExpression(expression);
        // 重启触发器
        // scheduler.resumeTrigger(triggerName, triggerGroupName);
      }
    } catch (Exception e) {
      log.error(e.getMessage(), e);

    }
  }

  /**
   * 移除任务
   * 
   * @param jobName
   */
  public static void removeJob(String jobName) {
    removeJob(jobName, JOB_GROUP_NAME, jobName, TRIGGER_GROUP_NAME);
  }

  public static void removeJob(String jobName, String jobGroupName, String triggerName, String triggerGroupName) {
    log.debug("removeJob:" + jobName);
    try {
      // Scheduler scheduler = schedulerFactory.getScheduler();
      // scheduler.pauseTrigger(triggerName, triggerGroupName);// 停止触发器
      // scheduler.unscheduleJob(triggerName, triggerGroupName);// 移除触发器
      // scheduler.deleteJob(jobName, jobGroupName);// 删除任务
    } catch (Exception e) {
      log.error(e.getMessage(), e);

    }
  }

  /**
   * 停止任务
   * 
   * @param jobName
   */
  public void pauseJob(String jobName) {
    pauseJob(jobName, JOB_GROUP_NAME);
  }

  public void pauseJob(String jobName, String jobGroupName) {
    log.debug("pauseJob:" + jobName);
    try {
      quartzScheduler.pauseJob(JobKey.jobKey(jobName, jobGroupName));

    } catch (Exception e) {
      log.error(e.getMessage(), e);

    }
  }

  /**
   * 立即执行任务
   * 
   * @param jobNam
   * @param dataMap
   */
  public void execJob(String jobName, JobDataMap dataMap) {
    execJob(jobName, JOB_GROUP_NAME, dataMap);
  }

  public void execJob(String jobName) {
    execJob(jobName, JOB_GROUP_NAME, new JobDataMap());
  }

  public void execJob(String jobName, String jobGroupName, JobDataMap dataMap) {
    log.debug("execJob:" + jobName);
    try {

      quartzScheduler.triggerJob(JobKey.jobKey(jobName, jobGroupName), dataMap);
    } catch (Exception e) {
      log.error(e.getMessage(), e);

    }
  }

  /**
   * 恢复任务
   * 
   * @param jobName
   */
  public void resumeJob(String jobName) {
    resumeJob(jobName, JOB_GROUP_NAME);
  }

  public void resumeJob(String jobName, String jobGroupName) {
    log.debug("resumeJob:" + jobName);
    try {
      quartzScheduler.resumeJob(JobKey.jobKey(jobName, jobGroupName));
    } catch (Exception e) {
      log.error(e.getMessage(), e);

    }
  }

  /**
   * 启动所有定时任务
   */
  public void startJobs() {
    log.debug("startJobs");
    try {
      if (quartzScheduler.isShutdown()) {
        quartzScheduler.start();
      }

    } catch (Exception e) {
      log.error(e.getMessage(), e);
    }
  }

  /**
   * 关闭所有定时任务
   */
  public void shutdownJobs() {
    log.debug("shutdownJobs");
    try {

      if (!quartzScheduler.isShutdown()) {
        quartzScheduler.shutdown();
      }

      // quartzScheduler.
    } catch (Exception e) {
      log.error(e.getMessage(), e);
    }
  }
}

参考文档

  1. 配置corn参考:http://www.cnblogs.com/skyblue/p/3296350.html
  2. 集群设置及原理参考:
    http://sundoctor.iteye.com/blog/486055
    http://blog.csdn.net/zxl315/article/details/10830105

  3. QuartzSchedulerThread核心代码:
    http://blog.csdn.net/cutesource/article/details/4965520

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值