当前位置: 首页 > news >正文

Quartz初级教程

一、Quartz简介

1. Quartz

  • Quartz是OpenSymphony开源组织在Job scheduling领域又一个开源项目,它可以与J2EE与J2SE应用程序相结合也可以单独使用。Quartz可以用来创建简单或为运行十个,百个,甚至是好几万个Jobs这样复杂的日程序表。Jobs可以做成标准的Java组件或 EJBs。
  • Quartz是一个任务日程管理系统,一个在预先确定(被纳入日程)的时间到达时,负责执行(或者通知)其他软件组件的系统。
  • Quartz用一个小Java库发布文件(.jar文件),这个库文件包含了所有Quartz核心功能。这些功能的主要接口(API)是Scheduler接口。

2. Quartz核心接口

  • Scheduler – 核心调度器
  • Job – 任务
  • JobDetail – 任务描述
  • Trigger -- 触发器
Job和JobDetail是同时相互依赖存在的,和触发器一起注册到核心调度器。
Quartz的执行过程: Scheduler--> Trigger --> JobDetail --> Job

3. Tigger

  • SimpleTrigger
  • CronTrigger

SimpleTrigger

  • SimpleTrigger用来触发只需执行一次或者在给定时间触发并且重复N次且每次执行延迟一定时间的任务。

CronTrigger

  • 像日历那样按日程来触发任务,而不是像SimpleTrigger 那样每隔特定的间隔时间触发,CronTriggers通常比SimpleTrigger更有用。

二、Cron Expressions

1. CronTrigger

CronTriggers往往比SimpleTrigger更有用,如果您需要基于日历的概念,而非SimpleTrigger完全指定的时间间隔,复发的发射工作的时间表。
CronTrigger,你可以指定触发的时间表如“每星期五中午”,或“每个工作日9:30时”,甚至“每5分钟一班9:00和10:00逢星期一上午,星期三星期五“。
即便如此,SimpleTrigger一样,CronTrigger拥有的startTime指定的时间表时生效,指定的时间表时,应停止(可选)结束时间。

2. Cron Expressions

cron的表达式被用来配置CronTrigger实例。 cron的表达式是字符串,实际上是由七子表达式,描述个别细节的时间表。这些子表达式是分开的空白,代表:

1 . 1. Seconds
2 . 2. Minutes
3 . 3. Hours
4 . 4. Day-of-Month
5 . 5. Month
6 . 6. Day-of-Week
7 . 7. Year (可选字段)

例: "0 0 12 ? * WED" 在每星期三下午12:00 执行。

个别子表达式可以包含范围, 例如,在前面的例子里("WED")可以替换成 "MON-FRI", "MON, WED, FRI"甚至"MON-WED,SAT".
“*” 代表整个时间段.
每一个字段都有一套可以指定有效值,如
Seconds (秒):可以用数字0-59 表示,
Minutes(分):可以用数字0-59 表示,
Hours(时):可以用数字0-23表示,
Day-of-Month(天):可以用数字1-31 中的任一一个值,但要注意一些特别的月份
Month(月):可以用0-11 或用字符串 “JAN, FEB, MAR, APR, MAY, JUN, JUL, AUG, SEP, OCT, NOV and DEC” 表示
Day-of-Week(每周):可以用数字1-7表示(1 = 星期日)或用字符口串“SUN, MON, TUE, WED, THU, FRI and SAT”表示

“/”:为特别单位,表示为“每”如“0/15”表示每隔15分钟执行一次,“0”表示为从“0”分开始, “3/20”表示表示每隔20分钟执行一次,“3”表示从第3分钟开始执行
“?”:表示每月的某一天,或第周的某一天
“L”:用于每月,或每周,表示为每月的最后一天,或每个月的最后星期几如“6L”表示“每月的最后一个星期五”
“W”:表示为最近工作日,如“15W”放在每月(day-of-month)字段上表示为“到本月15日最近的工作日”
““#”:是用来指定“的”每月第n个工作日,例 在每周(day-of-week)这个字段中内容为"6#3" or "FRI#3" 则表示“每月第三个星期五”

1). Cron表达式的格式:秒 分 时 日 月 周 年(可选)。

字段名允许的值允许的特殊字符
0-59, - * /
0-59, - * /
小时0-23, - * /
1-31, - * ? / L W C
1-12 or JAN-DEC, - * /
周几1-7 or SUN-SAT, - * ? / L C #
年(可选字段)empty, 1970-2099, - * /
 “?”字符:表示不确定的值
 “,”字符:指定数个值
 “-”字符:指定一个值的范围
 “/”字符:指定一个值的增加幅度。n/m表示从n开始,每次增加m
 “L”字符:用在日表示一个月中的最后一天,用在周表示该月最后一个星期X
 “W”字符:指定离给定日期最近的工作日(周一到周五)
 “#”字符:表示该月第几个周X。6#3表示该月第3个周五

2). Cron表达式范例:

每隔5秒执行一次:/5 * ?
每隔1分钟执行一次:0 /1 ?
每天23点执行一次:0 0 23 ?
每天凌晨1点执行一次:0 0 1 ?
每月1号凌晨1点执行一次:0 0 1 1 * ?
每月最后一天23点执行一次:0 0 23 L * ?
每周星期天凌晨1点实行一次:0 0 1 ? * L
在26分、29分、33分执行一次:0 26,29,33 * ?
每天的0点、13点、18点、21点都执行一次:0 0 0,13,18,21 ?

三、Quartz 触发器Tigger的简单案例

前面对Tigger进行过简单描述,现在用Demo进行演示

Quartz的Maven依赖

<dependency>
          <groupId>org.quartz-scheduler</groupId>
          <artifactId>quartz</artifactId>
          <version>2.2.1</version>
</dependency>

1 . 实现一个Job接口

/* 
 * All content copyright Terracotta, Inc., unless otherwise indicated. All rights reserved. 
 * 
 * Licensed under the Apache License, Version 2.0 (the "License"); you may not 
 * use this file except in compliance with the License. You may obtain a copy 
 * of the License at 
 * 
 *   http://www.apache.org/licenses/LICENSE-2.0 
 *   
 * Unless required by applicable law or agreed to in writing, software 
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 
 * License for the specific language governing permissions and limitations 
 * under the License.
 * 
 */
 
package org.ouhei.quartz.example;

import java.util.Date;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.quartz.Job;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;

/**
 * <p>
 * This is just a simple job that says "Hello" to the world.
 * </p>
 * 
 * @author Bill Kratzer
 */
public class HelloJob implements Job {

    private static Logger _log = LoggerFactory.getLogger(HelloJob.class);

    /**
     * <p>
     * Empty constructor for job initilization
     * </p>
     * <p>
     * Quartz requires a public empty constructor so that the
     * scheduler can instantiate the class whenever it needs.
     * </p>
     */
    public HelloJob() {
    }

    /**
     * <p>
     * Called by the <code>{@link org.quartz.Scheduler}</code> when a
     * <code>{@link org.quartz.Trigger}</code> fires that is associated with
     * the <code>Job</code>.
     * </p>
     * 
     * @throws JobExecutionException
     *             if there is an exception while executing the job.
     */
    public void execute(JobExecutionContext context)
        throws JobExecutionException {

        // Say Hello to the World and display the date/time
        _log.info("Hello World! - " + new Date());
    }

}

2 . SimpleTrigger触发器进行模拟

SimpleExample代码

/* 
 * All content copyright Terracotta, Inc., unless otherwise indicated. All rights reserved. 
 * 
 * Licensed under the Apache License, Version 2.0 (the "License"); you may not 
 * use this file except in compliance with the License. You may obtain a copy 
 * of the License at 
 * 
 *   http://www.apache.org/licenses/LICENSE-2.0 
 *   
 * Unless required by applicable law or agreed to in writing, software 
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 
 * License for the specific language governing permissions and limitations 
 * under the License.
 * 
 */

package org.ouhei.quartz.example;

import static org.quartz.DateBuilder.evenMinuteDate;
import static org.quartz.JobBuilder.newJob;
import static org.quartz.TriggerBuilder.newTrigger;

import org.quartz.JobDetail;
import org.quartz.Scheduler;
import org.quartz.SchedulerFactory;
import org.quartz.Trigger;
import org.quartz.impl.StdSchedulerFactory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.Date;

/**
 * This Example will demonstrate how to start and shutdown the Quartz scheduler and how to schedule
 * a job to run in Quartz.
 * 
 * @author Bill Kratzer
 */
public class SimpleExample {

    public void run() throws Exception {
        Logger log = LoggerFactory.getLogger(SimpleExample.class);

        log.info("------- Initializing ----------------------");

        // 定义调度器
        SchedulerFactory sf = new StdSchedulerFactory();
        Scheduler sched = sf.getScheduler();

        log.info("------- Initialization Complete -----------");

        // 获取当前时间的下一分钟
        Date runTime = evenMinuteDate(new Date());

        log.info("------- Scheduling Job  -------------------");

        // 定义job
        // 在quartz中,有组的概念,组+job名称 唯一的
        JobDetail job = newJob(HelloJob.class).withIdentity("job1", "group1").build();

        // 定义触发器,在下一分钟启动
        Trigger trigger = newTrigger().withIdentity("trigger1", "group1").startAt(runTime).build();

        // 将job注册到调度器
        sched.scheduleJob(job, trigger);
        log.info(job.getKey() + " will run at: " + runTime);

        // 启动调度器
        sched.start();

        log.info("------- Started Scheduler -----------------");

        // 等待65秒
        log.info("------- Waiting 65 seconds... -------------");
        try {
            // wait 65 seconds to show job
            Thread.sleep(65L * 1000L);
            // executing...
        } catch (Exception e) {
            //
        }

        // 关闭调度器
        log.info("------- Shutting Down ---------------------");
        sched.shutdown(true);
        log.info("------- Shutdown Complete -----------------");
    }

    public static void main(String[] args) throws Exception {

        SimpleExample example = new SimpleExample();
        example.run();

    }

}

3 . 添加日志文件log4j.properties

log4j.rootLogger=DEBUG,A1
log4j.logger.com.taotao = DEBUG
log4j.logger.org.mybatis = DEBUG

log4j.appender.A1=org.apache.log4j.ConsoleAppender
log4j.appender.A1.layout=org.apache.log4j.PatternLayout
log4j.appender.A1.layout.ConversionPattern=%-d{yyyy-MM-dd HH:mm:ss,SSS} [%t] [%c]-[%p] %m%n

运行main方法,观察控制台。


如果模拟CronTrigger触发器,把上述的SimpleExample代码用SimpleCronExample代码替换

SimpleCronExample代码:

/* 
 * All content copyright Terracotta, Inc., unless otherwise indicated. All rights reserved. 
 * 
 * Licensed under the Apache License, Version 2.0 (the "License"); you may not 
 * use this file except in compliance with the License. You may obtain a copy 
 * of the License at 
 * 
 *   http://www.apache.org/licenses/LICENSE-2.0 
 *   
 * Unless required by applicable law or agreed to in writing, software 
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 
 * License for the specific language governing permissions and limitations 
 * under the License.
 * 
 */

package org.ouhei.quartz.example;

import static org.quartz.CronScheduleBuilder.cronSchedule;
import static org.quartz.DateBuilder.evenMinuteDate;
import static org.quartz.JobBuilder.newJob;
import static org.quartz.TriggerBuilder.newTrigger;

import org.quartz.JobDetail;
import org.quartz.Scheduler;
import org.quartz.SchedulerFactory;
import org.quartz.Trigger;
import org.quartz.impl.StdSchedulerFactory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.Date;

/**
 * This Example will demonstrate how to start and shutdown the Quartz scheduler and how to schedule
 * a job to run in Quartz.
 * 
 * @author Bill Kratzer
 */
public class SimpleCronExample {

    public void run() throws Exception {
        Logger log = LoggerFactory.getLogger(SimpleCronExample.class);

        log.info("------- Initializing ----------------------");

        // 定义调度器
        SchedulerFactory sf = new StdSchedulerFactory();
        Scheduler sched = sf.getScheduler();

        log.info("------- Initialization Complete -----------");

        // 获取当前时间的下一分钟
        Date runTime = evenMinuteDate(new Date());

        log.info("------- Scheduling Job  -------------------");

        // 定义job
        JobDetail job = newJob(HelloJob.class).withIdentity("job1", "group1").build();

        // 定义触发器,每2秒执行一次
        Trigger trigger = newTrigger().withIdentity("trigger1", "group1")
                .withSchedule(cronSchedule("0 0/1 * * * ?")).build();

        // 将job注册到调度器
        sched.scheduleJob(job, trigger);
        log.info(job.getKey() + " will run at: " + runTime);

        // 启动调度器
        sched.start();

        log.info("------- Started Scheduler -----------------");

        // 等待1分钟
        log.info("------- Waiting 60 seconds... -------------");
        try {
            Thread.sleep(60L * 1000L);
        } catch (Exception e) {
            //
        }

        // 关闭调度器
        log.info("------- Shutting Down ---------------------");
        sched.shutdown(true);
        log.info("------- Shutdown Complete -----------------");
    }

    public static void main(String[] args) throws Exception {

        SimpleCronExample example = new SimpleCronExample();
        example.run();

    }

}

四、spring整合Quartz

前面用案例介绍过SimpleTrigger和CronTrigger,
下面用spring整合Quartz,分四步:

  1. 导入依赖
  2. 编写Job
  3. 编写spring配置文件
  4. 启动spring容器(启动调度器)

1. 导入maven依赖

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>
  <groupId>org.ouhei.quartz</groupId>
  <artifactId>ouhei-quartz</artifactId>
  <version>1.0.0-SNAPSHOT</version>
  <dependencies>
      <dependency>
          <groupId>org.springframework</groupId>
          <artifactId>spring-context-support</artifactId>
          <version>4.0.6.RELEASE</version>
      </dependency>
      <dependency>
          <groupId>org.quartz-scheduler</groupId>
          <artifactId>quartz</artifactId>
          <version>2.2.1</version>
      </dependency>
      <dependency>
          <groupId>org.slf4j</groupId>
          <artifactId>slf4j-log4j12</artifactId>
          <version>1.7.7</version>
      </dependency>
      <dependency>
          <groupId>org.springframework</groupId>
          <artifactId>spring-tx</artifactId>
          <version>4.0.6.RELEASE</version>
      </dependency>
  </dependencies>
</project>

2. 编写Job

package org.ouhei.quartz;

import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
import org.springframework.context.ApplicationContext;
import org.springframework.scheduling.quartz.QuartzJobBean;

/**
 * QuartzJobBean实现了Job接口
 * 
 */
public class MyJob extends QuartzJobBean {
    
    @Override
    protected void executeInternal(JobExecutionContext context) throws JobExecutionException {
        System.out.println("myJob 执行了............." + context.getTrigger().getKey().getName());
        ApplicationContext applicationContext = (ApplicationContext) context.getJobDetail().getJobDataMap()
                .get("applicationContext");
        System.out.println("获取到的Spring容器是: " + applicationContext);
        
    }

}

3. 编写spring配置文件applicationContext-scheduler.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:context="http://www.springframework.org/schema/context" xmlns:p="http://www.springframework.org/schema/p"
    xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
    http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd
    http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.0.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.0.xsd
    http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-4.0.xsd">

    <!-- 定义任务bean -->
    <bean name="myJobDetail" class="org.springframework.scheduling.quartz.JobDetailFactoryBean">
        <!-- 指定具体的job类 -->
        <property name="jobClass" value="org.ouhei.quartz.MyJob" />
        <!-- 指定job的名称 -->
        <property name="name" value="myJob" />
        <!-- 指定job的分组 -->
        <property name="group" value="jobs" />
        <!-- 必须设置为true,如果为false,当没有活动的触发器与之关联时会在调度器中删除该任务  -->
        <property name="durability" value="true"/>
        <!-- 指定spring容器的key,如果不设定在job中的jobmap中是获取不到spring容器的 -->
        <property name="applicationContextJobDataKey" value="applicationContext"/>
    </bean>
    
    <!-- 定义触发器 -->
    <bean id="cronTrigger" class="org.springframework.scheduling.quartz.CronTriggerFactoryBean">
        <property name="jobDetail" ref="myJobDetail" />
        <!-- 每5秒执行一次 -->
        <property name="cronExpression" value="0/5 * * * * ?" />
    </bean>
    
    <!-- 定义触发器 -->
    <!-- 演示:一个job可以有多个trigger;一个trigger只能有一个job -->
    <bean id="cronTrigger2" class="org.springframework.scheduling.quartz.CronTriggerFactoryBean">
        <property name="jobDetail" ref="myJobDetail" />
        <!-- 每一分钟执行一次 -->
        <property name="cronExpression" value="0 */1 * * * ?" />
    </bean>
    
    <!-- 定义调度器 -->
    <bean class="org.springframework.scheduling.quartz.SchedulerFactoryBean">
        <property name="triggers">
            <list>
                <ref bean="cronTrigger" />
                <ref bean="cronTrigger2" />
            </list>
        </property>
    </bean>

</beans>

4. 启动spring容器(启动调度器)

package org.ouhei.quartz;

import org.springframework.context.support.ClassPathXmlApplicationContext;

public class Main {
    
    public static void main(String[] args) {
        new ClassPathXmlApplicationContext("classpath:applicationContext-scheduler.xml");
    }

}

5. 添加日志文件

log4j.rootLogger=DEBUG,A1
log4j.logger.com.taotao = DEBUG
log4j.logger.org.mybatis = DEBUG

log4j.appender.A1=org.apache.log4j.ConsoleAppender
log4j.appender.A1.layout=org.apache.log4j.PatternLayout
log4j.appender.A1.layout.ConversionPattern=%-d{yyyy-MM-dd HH:mm:ss,SSS} [%t] [%c]-[%p] %m%n

相关文章:

  • Android程序的目录结构
  • MP实战系列(一)之入门框架搭建和使用
  • 【转】客户/服务器程序设计范式
  • 秒杀架构实践
  • 解决VMWare“Could not get vmci driver version句柄无效”的错误
  • WPF内嵌CEF控件,与JS交互
  • PHP sql注入漏洞修复(字符串型)
  • 【系列教程1】Gradle入门系列二:第一个Java项目
  • Java Concurrent -- 同步容器类
  • 发现心中的暴力
  • 人人都能学会的python编程教程16:map和reduce
  • PHP变量存储与赋值
  • 设计模式学习笔记(1)组合
  • diskpart
  • 统一登录中心SSO 单点登录系统的构想
  • 【css3】浏览器内核及其兼容性
  • Angular数据绑定机制
  • Git的一些常用操作
  • JavaScript对象详解
  • Java多态
  • Java深入 - 深入理解Java集合
  • overflow: hidden IE7无效
  • passportjs 源码分析
  • Selenium实战教程系列(二)---元素定位
  • 表单中readonly的input等标签,禁止光标进入(focus)的几种方式
  • 从零开始的无人驾驶 1
  • 分布式事物理论与实践
  • 基于HAProxy的高性能缓存服务器nuster
  • 每天10道Java面试题,跟我走,offer有!
  • 深入浅出Node.js
  • 通过获取异步加载JS文件进度实现一个canvas环形loading图
  • 写代码的正确姿势
  • 新书推荐|Windows黑客编程技术详解
  • 这几个编码小技巧将令你 PHP 代码更加简洁
  • 东超科技获得千万级Pre-A轮融资,投资方为中科创星 ...
  • 进程与线程(三)——进程/线程间通信
  • #Linux(Source Insight安装及工程建立)
  • #pragma pack(1)
  • #微信小程序:微信小程序常见的配置传旨
  • #我与Java虚拟机的故事#连载10: 如何在阿里、腾讯、百度、及字节跳动等公司面试中脱颖而出...
  • (2)(2.4) TerraRanger Tower/Tower EVO(360度)
  • (3)(3.2) MAVLink2数据包签名(安全)
  • (TOJ2804)Even? Odd?
  • (搬运以学习)flask 上下文的实现
  • (第8天)保姆级 PL/SQL Developer 安装与配置
  • (附程序)AD采集中的10种经典软件滤波程序优缺点分析
  • (附源码)springboot车辆管理系统 毕业设计 031034
  • (附源码)ssm高校升本考试管理系统 毕业设计 201631
  • (九十四)函数和二维数组
  • (利用IDEA+Maven)定制属于自己的jar包
  • (论文阅读22/100)Learning a Deep Compact Image Representation for Visual Tracking
  • (每日持续更新)jdk api之FileFilter基础、应用、实战
  • (三)c52学习之旅-点亮LED灯
  • (心得)获取一个数二进制序列中所有的偶数位和奇数位, 分别输出二进制序列。
  • (转)全文检索技术学习(三)——Lucene支持中文分词