Quartz定时任务的使用

Quartz 是一个功能丰富的开源作业调度库,Quartz 可用于创建简单或复杂的调度,以执行数十、数百甚至数万个作业;任务被定义为标准 Java 组件的作业,这些组件几乎可以执行任何您可以对其编程来执行的操作。Quartz Scheduler 包含许多企业级功能,例如对 JTA 事务和集群的支持。

核心

1)任务 Job

调度的任务都必须实现 org.quartz.job 接口,然后实现接口中定义的 execute( ) 方法即可

2)触发器 Trigger

Trigger 作为执行任务的调度器。如果想要凌晨1点执行备份数据的任务,那么 Trigger 就会设置凌晨1点执行该任务。其中 Trigger 又分为 SimpleTrigger 和 CronTrigger 两种

3)调度器 Scheduler

Scheduler 为任务的调度器,它会将任务 Job 及触发器 Trigger 整合起来,负责基于 Trigger 设定的时间来执行 Job

体系架构

quartz的基本使用

首先导入依赖

<!--quartz-->
<dependency>
    <groupId>org.quartz-scheduler</groupId>
    <artifactId>quartz</artifactId>
    <version>2.3.2</version>
</dependency>
SchedulerFactory schedFact = new org.quartz.impl.StdSchedulerFactory();

//创建调度器
  Scheduler sched = schedFact.getScheduler();

  sched.start();

  // define the job and tie it to our HelloJob class
  JobDetail job = newJob(HelloJob.class)
      .withIdentity("myJob", "group1")
      .build();

  // Trigger the job to run now, and then every 40 seconds
  Trigger trigger = newTrigger()
      .withIdentity("myTrigger", "group1")
      .startNow()
      .withSchedule(simpleSchedule()
          .withIntervalInSeconds(40)
          .repeatForever())
      .build();

  // Tell quartz to schedule the job using our trigger
  sched.scheduleJob(job, trigger);


  public class HelloJob implements Job {

    public HelloJob() {
    }

    public void execute(JobExecutionContext context)
      throws JobExecutionException
    {
      System.err.println("Hello!  HelloJob is executing.");
    }
  }

JobDataMap 可用于保存任何数量的(可序列化的)数据对象,在作业实例执行时这些数据对象可供作业实例使用。JobDataMap 是 Java Map 接口的一个实现,并且增加了一些方便的方法来存储和检索原始类型的数据。

 // define the job and tie it to our DumbJob class
  JobDetail job = newJob(DumbJob.class)
      .withIdentity("myJob", "group1") // name "myJob", group "group1"
      .usingJobData("jobSays", "Hello World!")
      .usingJobData("myFloatValue", 3.141f)
      .build();



//获取JobDetail中的数据
public class DumbJob implements Job {

    public DumbJob() {
    }

    public void execute(JobExecutionContext context)
      throws JobExecutionException
    {
      JobKey key = context.getJobDetail().getKey();

      JobDataMap dataMap = context.getJobDetail().getJobDataMap();

      String jobSays = dataMap.getString("jobSays");
      float myFloatValue = dataMap.getFloat("myFloatValue");

      System.err.println("Instance " + key + " of DumbJob says: " + jobSays + ", and val is: " + myFloatValue);
    }
  }

Trigger

分为simple Trigger  cron Trigger

//Simple Trigger
//为特定时刻构建触发器,然后每十秒重复十次:
trigger = newTrigger()
    .withIdentity("trigger3", "group1")
    .startAt(myTimeToStartFiring)  // if a start time is not given (if this line were omitted), "now" is implied
    .withSchedule(simpleSchedule()
        .withIntervalInSeconds(10)
        .withRepeatCount(10)) // note that 10 repeats will give a total of 11 firings
    .forJob(myJob) // identify job with handle to its JobDetail itself                   
    .build();


//构建一个触发器,该触发器将在周三上午 10:42 触发
trigger = newTrigger()
    .withIdentity("trigger3", "group1")
    .withSchedule(weeklyOnDayAndHourAndMinute(DateBuilder.WEDNESDAY, 10, 42))
    .forJob(myJobKey)
    .inTimeZone(TimeZone.getTimeZone("America/Los_Angeles"))
    .build();
//或者cron
trigger = newTrigger()
    .withIdentity("trigger3", "group1")
    .withSchedule(cronSchedule("0 42 10 ? * WED"))
    .inTimeZone(TimeZone.getTimeZone("America/Los_Angeles"))
    .forJob(myJobKey)
    .build();

在项目中的使用以伪代码表示

//定义抽象类
public abstract class AbstractQuartzJob implements Job {

 private static final ThreadLocal<Date> threadLocal = new ThreadLocal<>();


 @Override
    public void execute(JobExecutionContext context) throws JobExecutionException {
        try {
            before(context, job);
            doExecute(context, job);
            after(context, sysJob, null);
        } catch (Exception e) {
            log.error("任务执行异常  - :", e);
            after(context, job, e);
        }
    }
    /**
     * 执行前
     */
    protected void before(JobExecutionContext context, Dd sysJob) {
        threadLocal.set(new Date());
    }
    /**
     * 执行后
     */
    protected void after(JobExecutionContext context, Dd sysJob, Exception e) {
       //log 
    }
}

//具体实现类
//定时任务处理(禁止并发执行)
public class QuartzDisallowConcurrentExecution extends AbstractQuartzJob {
    @Override
    protected void doExecute(JobExecutionContext context, Dd job) throws Exception {
        JobInvokeUtil.invokeMethod(job);
    }
}

//定时任务处理(允许并发执行)
public class QuartzJobExecution extends AbstractQuartzJob {
    @Override
    protected void doExecute(JobExecutionContext context, Dd job) throws Exception {
        JobInvokeUtil.invokeMethod(job);
    }
}

public class JobInvokeUtil {

    /**
     * 执行方法
     */
    public static void invokeMethod(Dd job) throws Exception {

        String invokeTarget = job.getClassAndMethodName();
        String beanName = getBeanName(invokeTarget);
        String methodName = getMethodName(invokeTarget);
        List<Object[]> methodParams = getMethodParams(invokeTarget);
        if (!isValidClassName(beanName)) {
            Object bean = ApplicationContextProvider.getBean(beanName);
            invokeMethod(bean, methodName, methodParams);
        } else {
            Object bean = Class.forName(beanName).newInstance();
            invokeMethod(bean, methodName, methodParams);
        }
    }
}
public class ScheduleUtils {


/**
     * 创建定时任务
     */
    public static void createScheduleJob(Scheduler scheduler, Dd job) throws SchedulerException, TaskException {
        Class<? extends Job> jobClass = getQuartzJobClass(job);
        // 构建job信息
        Long jobId = job.getId();
        JobDetail jobDetail = JobBuilder.newJob(jobClass).withIdentity(jobGroup).build();

        // 表达式调度构建器    corn
        CronScheduleBuilder cronScheduleBuilder = CronScheduleBuilder.cronSchedule(job.getCron());
        cronScheduleBuilder = handleCronScheduleMisfirePolicy(job, cronScheduleBuilder);

        // 按新的cronExpression表达式构建一个新的trigger   trigger  key   corn表达式
        CronTrigger trigger = TriggerBuilder.newTrigger().withIdentity(jobGroup)
                .withSchedule(cronScheduleBuilder).build();

        // 放入参数,运行时的方法可以获取
        jobDetail.getJobDataMap().put(ScheduleConstants.TASK_PROPERTIES, job);

        // 判断是否存在
        if (scheduler.checkExists(getJobKey(jobId, jobGroup))) {
            // 防止创建时存在数据问题 先移除,然后在执行创建操作
            scheduler.deleteJob(getJobKey(jobId, jobGroup));
        }
        scheduler.scheduleJob(jobDetail, trigger);
    }

}

quartz集群分布式多节点的情况下

       在项目中使用分布式并发部署定时任务,多台跨JVM,按照常理逻辑每个JVM的定时任务会各自运行,这样就会存在问题,多台分布式JVM机器的应用服务同时干活,一个是加重服务负担,另外一个是存在严重的逻辑问题,比如需要回滚的数据,就回滚了多次,刚好quartz提供很好的解决方案。

       集群分布式并发环境中使用QUARTZ定时任务调度,会在各个节点会上报任务,存到数据库中,执行时会从数据库中取出触发器来执行,如果触发器的名称和执行时间相同,则只有一个节点去执行此任务。

        如果此节点执行失败,则此任务则会被分派到另一节点执行,中途也会自动检查失效的定时调度,发现不成功的,其他节点立马接过来继续完成定时任务。对应的定时任务调度表比较多,有11个。

  • 4
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值