Quartz代码详解

版权声明:转载请注明原创地址,否则依法追究法律责任 https://blog.csdn.net/weixin_38964895/article/details/81583275

前言

最近在工作中,借助于Quartz实现一个定时任务的跑批,下面简单总结下,以供大家参考讨论。

目录

  1. Quartz是做什么的?
  2. Quartz怎么做到的?
  3. 怎么用Quartz做到?
  1. Quartz是做什么的?

任务调度框架,比如你有这样的需求:

  1. 每周五更新远程数据库和本地数据库的数据
  2. 每月15号检查工资是否到账
  3. 每隔一周,对本地数据库核心表数据进行一次备份

简而言之,就是在客户指定的时间完成指定的事情,Quartz的职责就是完成这件事,我们给QUartz一个触发条件,Quartz负责到了时间点,触发相应的Job执行对应的任务。

2.Quartz怎么做到的?

首先看一段简单的Quartz入门代码

import static org.quartz.DateBuilder.newDate;

import static org.quartz.JobBuilder.newJob;

import static org.quartz.SimpleScheduleBuilder.simpleSchedule;

import static org.quartz.TriggerBuilder.newTrigger;


import java.util.GregorianCalendar;


import org.quartz.JobDetail;

import org.quartz.Scheduler;

import org.quartz.Trigger;

import org.quartz.impl.StdSchedulerFactory;

import org.quartz.impl.calendar.AnnualCalendar;


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();

        }

    }}

现在我们让他执行起来

import java.util.Date;

import org.quartz.DisallowConcurrentExecution;

import org.quartz.Job;

import org.quartz.JobDetail;

import org.quartz.JobExecutionContext;

import org.quartz.JobExecutionException;

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("hello " + name + " at " + new Date());

    }}

我们首先看几个关键字:

Scheduler

     调度器。所有的调度都是由它控制。Scheduler就是Quartz的大脑,所有任务都是由它来设施。

    Schduelr包含两个重要组件: JobStore和ThreadPool。

  JobStore是会来存储运行时信息的,包括Trigger,Schduler,JobDetail,业务锁等。它有多种实现RAMJob(内存实现),JobStoreTX(JDBC,事务由Quartz管理),JobStoreCMT(JDBC,使用容器事务),ClusteredJobStore(集群实现)、TerracottaJobStore(什么是Terractta)。

   ThreadPool就是线程池,Quartz有自己的线程池实现。所有任务的都会由线程池执行。

Trigger

    定义触发的条件。例子中,它的类型是SimpleTrigger,每隔1秒中执行一次(什么是SimpleTrigger下面会有详述)。

name和group

    JobDetail和Trigger都有name和group。

    name是它们在这个sheduler里面的唯一标识。如果我们要更新一个JobDetail定义,只需要设置一个name相同的JobDetail实例即可。

    group是一个组织单元,sheduler会提供一些对整组操作的API,比如 scheduler.resumeJobs()。

JobDetail & Job

    JobDetail 定义的是任务数据,而真正的执行逻辑是在Job中,例子中是HelloQuartz。 为什么设计成JobDetail + Job,不直接使用Job?这是因为任务是有可能并发执行,如果Scheduler直接使用Job,就会存在对同一个Job实例并发访问的问题。而JobDetail & Job 方式,sheduler每次执行,都会根据JobDetail创建一个新的Job实例,这样就可以规避并发访问的问题

Cron表达式

位置

时间域

允许值

特殊值

1

0-59

, - * /

2

分钟

0-59

, - * /

3

小时

0-23

, - * /

4

日期

1-31

, - * ? / L W C

5

月份

1-12

, - * /

6

星期

1-7

, - * ? / L C #

7

年份(可选)

1-31

, - * /

  • 星号():可用在所有字段中,表示对应时间域的每一个时刻,例如, 在分钟字段时,表示“每分钟”;
  • 问号(?):该字符只在日期和星期字段中使用,它通常指定为“无意义的值”,相当于点位符;
  • 减号(-):表达一个范围,如在小时字段中使用“10-12”,则表示从10到12点,即10,11,12;
  • 逗号(,):表达一个列表值,如在星期字段中使用“MON,WED,FRI”,则表示星期一,星期三和星期五;
  • 斜杠(/):x/y表达一个等步长序列,x为起始值,y为增量步长值。如在分钟字段中使用0/15,则表示为0,15,30和45秒,而5/15在分钟字段中表示5,20,35,50,你也可以使用*/y,它等同于0/y;
  • L:该字符只在日期和星期字段中使用,代表“Last”的意思,但它在两个字段中意思不同。L在日期字段中,表示这个月份的最后一天,如一月的31号,非闰年二月的28号;如果L用在星期中,则表示星期六,等同于7。但是,如果L出现在星期字段里,而且在前面有一个数值X,则表示“这个月的最后X天”,例如,6L表示该月的最后星期五;
  • W:该字符只能出现在日期字段里,是对前导日期的修饰,表示离该日期最近的工作日。例如15W表示离该月15号最近的工作日,如果该月15号是星期六,则匹配14号星期五;如果15日是星期日,则匹配16号星期一;如果15号是星期二,那结果就是15号星期二。但必须注意关联的匹配日期不能够跨月,如你指定1W,如果1号是星期六,结果匹配的是3号星期一,而非上个月最后的那天。W字符串只能指定单一日期,而不能指定日期范围;
  • LW组合:在日期字段可以组合使用LW,它的意思是当月的最后一个工作日;
  • 井号(#):该字符只能在星期字段中使用,表示当月某个工作日。如6#3表示当月的第三个星期五(6表示星期五,#3表示当前的第三个),而4#5表示当月的第五个星期三,假设当月没有第五个星期三,忽略不触发;
  • C:该字符只在日期和星期字段中使用,代表“Calendar”的意思。它的意思是计划所关联的日期,如果日期没有被关联,则相当于日历中所有日期。例如5C在日期字段中就相当于日历5日以后的第一天。1C在星期字段中相当于星期日后的第一天。

Cron表达式对特殊字符的大小写不敏感,对代表星期的缩写英文大小写也不敏感。

一些例子:

表示式

说明

0 0 12 * * ?

每天12点运行

0 15 10 ? * *

每天10:15运行

0 15 10 * * ?

每天10:15运行

0 15 10 * * ? *

每天10:15运行

0 15 10 * * ? 2008

在2008年的每天10:15运行

0 * 14 * * ?

每天14点到15点之间每分钟运行一次,开始于14:00,结束于14:59。

0 0/5 14 * * ?

每天14点到15点每5分钟运行一次,开始于14:00,结束于14:55。

0 0/5 14,18 * * ?

每天14点到15点每5分钟运行一次,此外每天18点到19点每5钟也运行一次。

0 0-5 14 * * ?

每天14:00点到14:05,每分钟运行一次。

0 10,44 14 ? 3 WED

3月每周三的14:10分到14:44,每分钟运行一次。

0 15 10 ? * MON-FRI

每周一,二,三,四,五的10:15分运行。

0 15 10 15 * ?

每月15日10:15分运行。

0 15 10 L * ?

每月最后一天10:15分运行。

0 15 10 ? * 6L

每月最后一个星期五10:15分运行。

0 15 10 ? * 6L 2007-2009

在2007,2008,2009年每个月的最后一个星期五的10:15分运行。

0 15 10 ? * 6#3

每月第三个星期五的10:15分运行。

3. 怎么用Quartz做到?

在我的项目中,使用到的非常简单,完全借助于Spring进行管理,配置一个Spring-quartz.xml文件,在改文件中制定类和方法名,并设置好cron表达式,即执行时间,到了指定的时间就会去我们指定的类中寻找制定的方法,并执行相关程序。下面贴上借助于Spring管理的实现步骤。

  1. Maven中引入jar包
<dependency>

  <groupId>org.quartz-scheduler</groupId>

  <artifactId>quartz</artifactId>

  <version>2.2.3</version>

</dependency>

    2.编辑配置文件

<?xml version=”1.0” encoding=”UTF-8”>



<beans>

  <bean class=”org.springframework.schelduling.quartz.SchedulerFactoryBean”>

     <property  name=”triggers”>

         <list>

             <!-- 加载指定id的cron-->

             <ref=”testUpdateTrigger”>

         <list>

     </property>

  </bean>

  <!-- 指定类-->

  <bean id=”testUpdateJob”  class=”com.test.testUpdateJob”></bean>

  <bean id=”testBean” 

        Class=”org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean”>

      <!-- 加载指定类-->

      <property name=”targetObject” ref=”testUpdateJob”/>

      <!-- 指定方法-->

      <property name=”targetMethod” ref=”testUpdate”/>

  </bean>



  <bean id=”testUpdateTrigger” 

      Class=”org.springframework.scheduling.quartz.CronTriggerFactoryBean”>

      <!-- 加载上面指定Job-->

      <property name=”JobDetail” ref=”testBean”/>

      <!-- 指定执行时间:8月11号凌晨1点执行-->

      <property name=”cronExpression” ref=”0 0 1 11 8 ?”/>

  </bean>



</beans>

   3.编写对应的方法

Package com.test;

Public class testUpdateJob {

  //  对应配置文件的指定类,制定方法名

  Public void testUpdate() {

     System.out.println(“Hello Quartz”);

  }

}

 

 

 

猜你喜欢

转载自blog.csdn.net/weixin_38964895/article/details/81583275