阿里云-云小站(无限量代金券发放中)
【腾讯云】云服务器、云数据库、COS、CDN、短信等热卖云产品特惠抢购

Quartz2.0以上版本的单机和集群

427次阅读
没有评论

共计 36685 个字符,预计需要花费 92 分钟才能阅读完成。

(一)Quartz 单机

1.Quartz 简介

Quartz 是一个完全由 java 编写的开源作业调度框架,能实现业务的定时调度。Quartz 主要有三个核心调度器、任务和触发器:

①任务 -JobDetail:Quartz 在任务调度的时候,需要创建一个任务实例,JobDetail 正是承担这个角色。在 Quartz2.0 以前的版本中,创建一个任务通过 new JobDetail(String jobName, String gruop, Class jobCLass)这个方法来创建,在 2.0 之后的版本中通过 JobBuilder 来创建任务。Job 接口中只有一个方法 void execute(JobExecutionContext context) throws JobExecutionException,因此在任务调度时,只需要实现 execute 方法就可以了,使用起来很方便。

②触发器 -Trigger:定义 Job 的执行时间、次数等信息,有 SimpleTrigger 和 CronTrigger 两种类型。当你需要的是一次性的调度,或者你需要在指定的时间激活某个任务并执行 N 次,设置每次任务执行的间隔时间 T。那此时使用 SimpleTrigger 将是非常方便的。如果你想在每周的周一 7:00 或者每月的第 2,3 天实现任务调度,这时候就需要用到 CronTrigger,CronTrigger 能够提供复杂的触发器表达式满足我们的需求。同时需要提到的一点是 Quartz 还提供很多日期的实现类 DateBuilder 等,在实际使用中很方便。

③调度器 -Scheduler:Quartz 框架的核心是调度器。调度器负责管理 Quartz 应用运行时环境。调度器不是靠自己做所有的工作,而是依赖框架内一些非常重要的部件。Quartz 不仅仅是线程和线程管理。为确保可伸缩性,Quartz 采用了基于多线程的架构。启动时,框架初始化一套 worker 线程,这套线程被调度器用来执行预定的作业。这就是 Quartz 怎样能并发运行多个作业的原理。Quartz 依赖一套松耦合的线程池管理部件来管理线程环境。

Spring3.2.11 与 Quartz2.2.1 整合时内存泄漏问题解决  http://www.linuxidc.com/Linux/2015-06/119042.htm

Spring 配置 Quartz 任务调度框架教程  http://www.linuxidc.com/Linux/2014-11/108907.htm

Quartz 深入浅出 http://www.linuxidc.com/Linux/2014-09/107007.htm

Quartz1.6 有状态 JOB 碰到的棘手问题既解决方案 http://www.linuxidc.com/Linux/2014-09/107005.htm

Spring 3 整合 Quartz 2 实现定时任务 http://www.linuxidc.com/Linux/2014-09/107006.htm

Java 项目中定时任务之 Quartz 的应用 http://www.linuxidc.com/Linux/2013-12/94443.htm

Spring 3 调度器示例 —— JDK 定时器和 Quartz 展示 http://www.linuxidc.com/Linux/2013-10/91946.htm

Quartz 框架 实现任务调度 http://www.linuxidc.com/Linux/2016-11/136778.htm

Spring Quartz 定时任务 http://www.linuxidc.com/Linux/2016-11/137525.htm

2. 搭建 Quartz 工程

①创建一个新工程

新建文件 lib 作为外部 jar 包,Quartz 最新版本通过官网可以下载 http://www.quartz-scheduler.org/downloads/。 导入你下载的 quartz 包,新建 package 为 com.example.singleQuartz, 里面就两个简单的类 SingleQuartzJob 和 SingleQuartzServer。SingleQuartzJob 定义 Job 的实现类,SingleQuartzServer 任务调度服务。

Quartz2.0 以上版本的单机和集群

②SingleQuartzJob.java 定义 Job 的实现类

package com.example.singleQuartz;

import org.quartz.Job;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;

import java.util.Date;

/**
 * Created by XuHui on 2016/12/22.
 */
public class SingleQuartzJob implements Job {
    @Override
    public void execute(JobExecutionContext context) throws JobExecutionException {System.out.print("Hello, Quartz! - executing its JOB at"+
                new Date() + "by" + context.getTrigger().getJobKey() + "\n");
    }
}

③SingleQuartzServer.java 实现任务调度

package com.example.singleQuartz;

import org.quartz.*;
import org.quartz.impl.StdSchedulerFactory;

import java.util.Date;
import java.util.concurrent.TimeUnit;

/**
 * Created by XuHui on 2016/12/22.
 */
public class SingleQuartzServer {public static void main(String[] args) throws SchedulerException {/* 获取 Scheduler 实例 */
        SchedulerFactory factory = new StdSchedulerFactory();
        Scheduler scheduler = factory.getScheduler();

        /* 启动调度器 */
        scheduler.start();

        /* 任务:withIdentity(String name, String group),其中 groupName 可以自己定义,也可以用 Scheduler 提供的 DEFAULT_GROUP。这里要求同组里面的 jobName 不能相同*/
        JobDetail jobDetail = JobBuilder.newJob(SingleQuartzJob.class)
                .withIdentity("job", Scheduler.DEFAULT_GROUP)
                .build();

        /*触发器:SimpleTrigger 和 CronTrigger。实现的功能是:接下来 30s 后执行 job,以后每个 10s 执行一次,重复 10 次,一共执行 11 次。nextGivenSecondDate(null, 30)距离现在时间 30s 之后执行 job,此处 null 可写作 new Date(), 可自行在 api 查看源码实现 */
        Date startTime = DateBuilder.nextGivenSecondDate(null, 30);
        SimpleTrigger simpleTrigger = TriggerBuilder.newTrigger()
                .withIdentity("trigger", Scheduler.DEFAULT_GROUP)
                .startAt(startTime)
                .withSchedule(SimpleScheduleBuilder.simpleSchedule()
                        .withIntervalInSeconds(10)
                        .withRepeatCount(10))
                .forJob(jobDetail)
                .build();

        /* 交由调度器调度 Job */
        scheduler.scheduleJob(jobDetail, simpleTrigger);

        /* 3 分钟任务调度之后关闭调度器 */
        try{TimeUnit.MINUTES.sleep(3);
        } catch (Exception e) {e.printStackTrace();
        } finally {scheduler.shutdown();
        }
    }
}

④执行任务调度

执行 run->main 但是发现报错了。此时是少了两个个日志包,slf4j-api-1.7.22.jar 和 slf4j-simple-1.7.22.jar,我们只要添加 slf4j 包就可以了。

通过官网可以下载http://www.slf4j.org/download.html,找到这两个包放到 lib 下就可以了。

Exception in thread "main" java.lang.NoClassDefFoundError: org/slf4j/LoggerFactory
    at org.quartz.impl.StdSchedulerFactory.<init>(StdSchedulerFactory.java:303)
    at com.example.singleQuartz.SingleQuartzServer.main(SingleQuartzServer.java:15)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
    at java.lang.reflect.Method.invoke(Unknown Source)
    at com.intellij.rt.execution.application.AppMain.main(AppMain.java:144)
Caused by: java.lang.ClassNotFoundException: org.slf4j.LoggerFactory
    at java.net.URLClassLoader.findClass(Unknown Source)
    at java.lang.ClassLoader.loadClass(Unknown Source)
    at sun.misc.Launcher$AppClassLoader.loadClass(Unknown Source)
    at java.lang.ClassLoader.loadClass(Unknown Source)
    ... 7 more

解决完上面日志包的问题,我们运行上面程序可以看到正常的调度结果如下。


[main] INFO org.quartz.core.QuartzScheduler - Scheduler DefaultQuartzScheduler_$_NON_CLUSTERED started.
Hello, Quartz! - executing its JOB at Thu Dec 22 19:40:30 CST 2016 by DEFAULT.job
Hello, Quartz! - executing its JOB at Thu Dec 22 19:40:40 CST 2016 by DEFAULT.job
Hello, Quartz! - executing its JOB at Thu Dec 22 19:40:50 CST 2016 by DEFAULT.job
Hello, Quartz! - executing its JOB at Thu Dec 22 19:41:00 CST 2016 by DEFAULT.job
Hello, Quartz! - executing its JOB at Thu Dec 22 19:41:10 CST 2016 by DEFAULT.job
Hello, Quartz! - executing its JOB at Thu Dec 22 19:41:20 CST 2016 by DEFAULT.job
Hello, Quartz! - executing its JOB at Thu Dec 22 19:41:30 CST 2016 by DEFAULT.job
Hello, Quartz! - executing its JOB at Thu Dec 22 19:41:40 CST 2016 by DEFAULT.job
Hello, Quartz! - executing its JOB at Thu Dec 22 19:41:50 CST 2016 by DEFAULT.job
Hello, Quartz! - executing its JOB at Thu Dec 22 19:42:00 CST 2016 by DEFAULT.job
Hello, Quartz! - executing its JOB at Thu Dec 22 19:42:10 CST 2016 by DEFAULT.job
[main] INFO org.quartz.core.QuartzScheduler - Scheduler DefaultQuartzScheduler_$_NON_CLUSTERED shutting down.
[main] INFO org.quartz.core.QuartzScheduler - Scheduler DefaultQuartzScheduler_$_NON_CLUSTERED paused.
[main] INFO org.quartz.core.QuartzScheduler - Scheduler DefaultQuartzScheduler_$_NON_CLUSTERED shutdown complete.

 ⑤任务调度的多线程

Scheduler 是存在多对多的关系,由于线程池的存在,调度器实现多线程并发执行任务调度,直接看下面 demo 就能明白。

package com.example.singleQuartz;

import org.quartz.*;
import org.quartz.impl.StdSchedulerFactory;

import java.util.Date;
import java.util.concurrent.TimeUnit;

/**
 * Created by XuHui on 2016/12/22.
 */
public class SingleQuartzThreadPoolServer {public static void main(String[] args) throws SchedulerException {/* 获取 Scheduler 实例 */
        SchedulerFactory factory = new StdSchedulerFactory();
        Scheduler scheduler = factory.getScheduler();

        /* 启动调度器 */
        scheduler.start();

        /******************************************************* Job-1 ****************************************************************/
        /* 任务:withIdentity(String name, String group),其中 groupName 可以自己定义,也可以用 Scheduler 提供的 DEFAULT_GROUP。这里要求同组里面的 jobName 不能相同*/
        JobDetail jobDetail = JobBuilder.newJob(SingleQuartzJob.class)
                .withIdentity("job1", Scheduler.DEFAULT_GROUP)
                .build();

        /*触发器:SimpleTrigger 和 CronTrigger。实现的功能是:接下来 30s 后执行 job,以后每个 10s 执行一次,重复 10 次,一共执行 11 次。nextGivenSecondDate(null, 30)距离现在时间 30s 之后执行 job,此处 null 可写作 new Date(), 可自行在 api 查看源码实现 */
        Date startTime = DateBuilder.nextGivenSecondDate(null, 30);
        SimpleTrigger simpleTrigger = TriggerBuilder.newTrigger()
                .withIdentity("trigger1", Scheduler.DEFAULT_GROUP)
                .startAt(startTime)
                .withSchedule(SimpleScheduleBuilder.simpleSchedule()
                        .withIntervalInSeconds(10)
                        .withRepeatCount(2))
                .forJob(jobDetail)
                .build();

        /* 交由调度器调度 Job */
        scheduler.scheduleJob(jobDetail, simpleTrigger);

        /******************************************************* Job-2 ****************************************************************/
        jobDetail = JobBuilder.newJob(SingleQuartzJob.class)
                .withIdentity("job2", Scheduler.DEFAULT_GROUP)
                .build();

        simpleTrigger = TriggerBuilder.newTrigger()
                .withIdentity("trigger2", Scheduler.DEFAULT_GROUP)
                .startAt(startTime)
                .withSchedule(SimpleScheduleBuilder.simpleSchedule()
                        .withIntervalInSeconds(10)
                        .withRepeatCount(2))
                .forJob(jobDetail)
                .build();
        scheduler.scheduleJob(jobDetail, simpleTrigger);

        /******************************************************* Job-3 ****************************************************************/
        jobDetail = JobBuilder.newJob(SingleQuartzJob.class)
                .withIdentity("job3", Scheduler.DEFAULT_GROUP)
                .build();

        simpleTrigger = TriggerBuilder.newTrigger()
                .withIdentity("trigger3", Scheduler.DEFAULT_GROUP)
                .startAt(startTime)
                .withSchedule(SimpleScheduleBuilder.simpleSchedule()
                        .withIntervalInSeconds(10)
                        .withRepeatCount(2))
                .forJob(jobDetail)
                .build();
        scheduler.scheduleJob(jobDetail, simpleTrigger);

        /* 2 分钟任务调度之后关闭调度器 */
        try{TimeUnit.MINUTES.sleep(2);
        } catch (Exception e) {e.printStackTrace();
        } finally {scheduler.shutdown();
        }
    }

}

执行结果如下:

[main] INFO org.quartz.core.QuartzScheduler - Scheduler DefaultQuartzScheduler_$_NON_CLUSTERED started.
Hello, Quartz! - executing its JOB at Thu Dec 22 19:52:30 CST 2016 by DEFAULT.job1
Hello, Quartz! - executing its JOB at Thu Dec 22 19:52:30 CST 2016 by DEFAULT.job2
Hello, Quartz! - executing its JOB at Thu Dec 22 19:52:30 CST 2016 by DEFAULT.job3
Hello, Quartz! - executing its JOB at Thu Dec 22 19:52:40 CST 2016 by DEFAULT.job3
Hello, Quartz! - executing its JOB at Thu Dec 22 19:52:40 CST 2016 by DEFAULT.job1
Hello, Quartz! - executing its JOB at Thu Dec 22 19:52:40 CST 2016 by DEFAULT.job2
Hello, Quartz! - executing its JOB at Thu Dec 22 19:52:50 CST 2016 by DEFAULT.job1
Hello, Quartz! - executing its JOB at Thu Dec 22 19:52:50 CST 2016 by DEFAULT.job3
Hello, Quartz! - executing its JOB at Thu Dec 22 19:52:50 CST 2016 by DEFAULT.job2
[main] INFO org.quartz.core.QuartzScheduler - Scheduler DefaultQuartzScheduler_$_NON_CLUSTERED shutting down.
[main] INFO org.quartz.core.QuartzScheduler - Scheduler DefaultQuartzScheduler_$_NON_CLUSTERED paused.
[main] INFO org.quartz.core.QuartzScheduler - Scheduler DefaultQuartzScheduler_$_NON_CLUSTERED shutdown complete.

 (二)任务调度持久到数据库

1. 建立数据库和建表

上面的例子的任务是存在内存中的,如果程序关闭任务就会消失,为了保持任务的可持久性,需要将任务调度存到数据库中。在你下载的 quartz 包下找到 quartz-2.2.1\docs\dbTables\,找到你对应的数据库建表语言,这里我用的是 mysql 数据库 tables_mysql.sql。在你本地或者服务器数据库新建一个数据库 quartz(你可以不建,主要为了和其他数据库区分)。将以下的建表语言导入该数据库。

#
# Quartz seems to work best with the driver mm.mysql-2.0.7-bin.jar
#
# PLEASE consider using mysql with innodb tables to avoid locking issues
#
# In your Quartz properties file, you'll need to set 
# org.quartz.jobStore.driverDelegateClass = org.quartz.impl.jdbcjobstore.StdJDBCDelegate
#

DROP TABLE IF EXISTS QRTZ_FIRED_TRIGGERS;
DROP TABLE IF EXISTS QRTZ_PAUSED_TRIGGER_GRPS;
DROP TABLE IF EXISTS QRTZ_SCHEDULER_STATE;
DROP TABLE IF EXISTS QRTZ_LOCKS;
DROP TABLE IF EXISTS QRTZ_SIMPLE_TRIGGERS;
DROP TABLE IF EXISTS QRTZ_SIMPROP_TRIGGERS;
DROP TABLE IF EXISTS QRTZ_CRON_TRIGGERS;
DROP TABLE IF EXISTS QRTZ_BLOB_TRIGGERS;
DROP TABLE IF EXISTS QRTZ_TRIGGERS;
DROP TABLE IF EXISTS QRTZ_JOB_DETAILS;
DROP TABLE IF EXISTS QRTZ_CALENDARS;


CREATE TABLE QRTZ_JOB_DETAILS
  (SCHED_NAME VARCHAR(120) NOT NULL,
    JOB_NAME  VARCHAR(200) NOT NULL,
    JOB_GROUP VARCHAR(200) NOT NULL,
    DESCRIPTION VARCHAR(250) NULL,
    JOB_CLASS_NAME   VARCHAR(250) NOT NULL,
    IS_DURABLE VARCHAR(1) NOT NULL,
    IS_NONCONCURRENT VARCHAR(1) NOT NULL,
    IS_UPDATE_DATA VARCHAR(1) NOT NULL,
    REQUESTS_RECOVERY VARCHAR(1) NOT NULL,
    JOB_DATA BLOB NULL,
    PRIMARY KEY (SCHED_NAME,JOB_NAME,JOB_GROUP)
);

CREATE TABLE QRTZ_TRIGGERS
  (SCHED_NAME VARCHAR(120) NOT NULL,
    TRIGGER_NAME VARCHAR(200) NOT NULL,
    TRIGGER_GROUP VARCHAR(200) NOT NULL,
    JOB_NAME  VARCHAR(200) NOT NULL,
    JOB_GROUP VARCHAR(200) NOT NULL,
    DESCRIPTION VARCHAR(250) NULL,
    NEXT_FIRE_TIME BIGINT(13) NULL,
    PREV_FIRE_TIME BIGINT(13) NULL,
    PRIORITY INTEGER NULL,
    TRIGGER_STATE VARCHAR(16) NOT NULL,
    TRIGGER_TYPE VARCHAR(8) NOT NULL,
    START_TIME BIGINT(13) NOT NULL,
    END_TIME BIGINT(13) NULL,
    CALENDAR_NAME VARCHAR(200) NULL,
    MISFIRE_INSTR SMALLINT(2) NULL,
    JOB_DATA BLOB NULL,
    PRIMARY KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP),
    FOREIGN KEY (SCHED_NAME,JOB_NAME,JOB_GROUP)
        REFERENCES QRTZ_JOB_DETAILS(SCHED_NAME,JOB_NAME,JOB_GROUP)
);

CREATE TABLE QRTZ_SIMPLE_TRIGGERS
  (SCHED_NAME VARCHAR(120) NOT NULL,
    TRIGGER_NAME VARCHAR(200) NOT NULL,
    TRIGGER_GROUP VARCHAR(200) NOT NULL,
    REPEAT_COUNT BIGINT(7) NOT NULL,
    REPEAT_INTERVAL BIGINT(12) NOT NULL,
    TIMES_TRIGGERED BIGINT(10) NOT NULL,
    PRIMARY KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP),
    FOREIGN KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP)
        REFERENCES QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP)
);

CREATE TABLE QRTZ_CRON_TRIGGERS
  (SCHED_NAME VARCHAR(120) NOT NULL,
    TRIGGER_NAME VARCHAR(200) NOT NULL,
    TRIGGER_GROUP VARCHAR(200) NOT NULL,
    CRON_EXPRESSION VARCHAR(200) NOT NULL,
    TIME_ZONE_ID VARCHAR(80),
    PRIMARY KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP),
    FOREIGN KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP)
        REFERENCES QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP)
);

CREATE TABLE QRTZ_SIMPROP_TRIGGERS
  (SCHED_NAME VARCHAR(120) NOT NULL,
    TRIGGER_NAME VARCHAR(200) NOT NULL,
    TRIGGER_GROUP VARCHAR(200) NOT NULL,
    STR_PROP_1 VARCHAR(512) NULL,
    STR_PROP_2 VARCHAR(512) NULL,
    STR_PROP_3 VARCHAR(512) NULL,
    INT_PROP_1 INT NULL,
    INT_PROP_2 INT NULL,
    LONG_PROP_1 BIGINT NULL,
    LONG_PROP_2 BIGINT NULL,
    DEC_PROP_1 NUMERIC(13,4) NULL,
    DEC_PROP_2 NUMERIC(13,4) NULL,
    BOOL_PROP_1 VARCHAR(1) NULL,
    BOOL_PROP_2 VARCHAR(1) NULL,
    PRIMARY KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP),
    FOREIGN KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP) 
    REFERENCES QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP)
);

CREATE TABLE QRTZ_BLOB_TRIGGERS
  (SCHED_NAME VARCHAR(120) NOT NULL,
    TRIGGER_NAME VARCHAR(200) NOT NULL,
    TRIGGER_GROUP VARCHAR(200) NOT NULL,
    BLOB_DATA BLOB NULL,
    PRIMARY KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP),
    FOREIGN KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP)
        REFERENCES QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP)
);

CREATE TABLE QRTZ_CALENDARS
  (SCHED_NAME VARCHAR(120) NOT NULL,
    CALENDAR_NAME  VARCHAR(200) NOT NULL,
    CALENDAR BLOB NOT NULL,
    PRIMARY KEY (SCHED_NAME,CALENDAR_NAME)
);

CREATE TABLE QRTZ_PAUSED_TRIGGER_GRPS
  (SCHED_NAME VARCHAR(120) NOT NULL,
    TRIGGER_GROUP  VARCHAR(200) NOT NULL, 
    PRIMARY KEY (SCHED_NAME,TRIGGER_GROUP)
);

CREATE TABLE QRTZ_FIRED_TRIGGERS
  (SCHED_NAME VARCHAR(120) NOT NULL,
    ENTRY_ID VARCHAR(95) NOT NULL,
    TRIGGER_NAME VARCHAR(200) NOT NULL,
    TRIGGER_GROUP VARCHAR(200) NOT NULL,
    INSTANCE_NAME VARCHAR(200) NOT NULL,
    FIRED_TIME BIGINT(13) NOT NULL,
    SCHED_TIME BIGINT(13) NOT NULL,
    PRIORITY INTEGER NOT NULL,
    STATE VARCHAR(16) NOT NULL,
    JOB_NAME VARCHAR(200) NULL,
    JOB_GROUP VARCHAR(200) NULL,
    IS_NONCONCURRENT VARCHAR(1) NULL,
    REQUESTS_RECOVERY VARCHAR(1) NULL,
    PRIMARY KEY (SCHED_NAME,ENTRY_ID)
);

CREATE TABLE QRTZ_SCHEDULER_STATE
  (SCHED_NAME VARCHAR(120) NOT NULL,
    INSTANCE_NAME VARCHAR(200) NOT NULL,
    LAST_CHECKIN_TIME BIGINT(13) NOT NULL,
    CHECKIN_INTERVAL BIGINT(13) NOT NULL,
    PRIMARY KEY (SCHED_NAME,INSTANCE_NAME)
);

CREATE TABLE QRTZ_LOCKS
  (SCHED_NAME VARCHAR(120) NOT NULL,
    LOCK_NAME  VARCHAR(40) NOT NULL, 
    PRIMARY KEY (SCHED_NAME,LOCK_NAME)
);


commit;

2. 导入 mysql 数据库的 jdbc 驱动包,mysql-connector-java-5.1.40-bin.jar

更多详情见请继续阅读下一页的精彩内容:http://www.linuxidc.com/Linux/2016-12/138743p2.htm

3. 配置 Quartz 配置文件 quartz.properities

org.quartz.scheduler.instanceName = MyScheduler
org.quartz.threadPool.threadCount = 3
org.quartz.jobStore.class = org.quartz.impl.jdbcjobstore.JobStoreTX
org.quartz.jobStore.driverDelegateClass = org.quartz.impl.jdbcjobstore.StdJDBCDelegate
org.quartz.jobStore.tablePrefix = QRTZ_
org.quartz.jobStore.dataSource = myDS

org.quartz.dataSource.myDS.driver = com.mysql.jdbc.Driver
org.quartz.dataSource.myDS.URL = jdbc:mysql://localhost:3306/quartz?characterEncoding=utf-8
org.quartz.dataSource.myDS.user = root
org.quartz.dataSource.myDS.password = 123456
org.quartz.dataSource.myDS.maxConnections = 5

4. 任务调度的持久性

其实介绍这部分主要是为了后面的 Quartz 集群做铺垫。为了验证任务调度的可持久性,我们从这两方面验证,当我们程序停止运行的时候,查看数据库能查看到任务调度的数据;当重新启动同一调度器的时候,原来的任务能继续执行。SingleQuartzKeepAlive.java 如下,其实和上面的 SingleQuartzServer 基本一样,只是加载了 Quartz 配置文件。

package com.example.singleQuartz;

import org.quartz.*;
import org.quartz.impl.StdSchedulerFactory;

import java.util.Date;
import java.util.concurrent.TimeUnit;

/**
 * Created by XuHui on 2016/12/22.
 */
public class SingleQuartzKeepAlive {public static void main(String[] args) throws SchedulerException {/* 获取 Scheduler 实例 */
        StdSchedulerFactory factory = new StdSchedulerFactory();
        factory.initialize("quartz.properities");
        Scheduler scheduler = factory.getScheduler();

        /* 启动调度器 */
        scheduler.start();

        JobDetail jobDetail = JobBuilder.newJob(SingleQuartzJob.class)
                .withIdentity("job", Scheduler.DEFAULT_GROUP)
                .build();

        Date startTime = DateBuilder.nextGivenSecondDate(null, 30);
        SimpleTrigger simpleTrigger = (SimpleTrigger) TriggerBuilder.newTrigger()
                .withIdentity("trigger", Scheduler.DEFAULT_GROUP)
                .startAt(startTime)
                .withSchedule(SimpleScheduleBuilder.simpleSchedule()
                        .withIntervalInSeconds(10)
                        .withRepeatCount(10))
                .forJob(jobDetail)
                .build();

        /* 交由调度器调度 Job */
        scheduler.scheduleJob(jobDetail, simpleTrigger);

        /* 3 分钟任务调度之后关闭调度器 */
        try{TimeUnit.MINUTES.sleep(3);
        } catch (Exception e) {e.printStackTrace();
        } finally {scheduler.shutdown();
        }
    }
}

我们 run->main 发现报错了,报错如下。这个因为我们缺少了 c3p0-0.9.1.2.jar,下载地址为 http://www.mchange.com/projects/c3p0/index.html。将这个包加入 lib 中即可。

Exception in thread "main" java.lang.NoClassDefFoundError: com/mchange/v2/c3p0/ComboPooledDataSource
    at org.quartz.utils.PoolingConnectionProvider.initialize(PoolingConnectionProvider.java:210)
    at org.quartz.utils.PoolingConnectionProvider.<init>(PoolingConnectionProvider.java:155)
    at org.quartz.impl.StdSchedulerFactory.instantiate(StdSchedulerFactory.java:1014)
    at org.quartz.impl.StdSchedulerFactory.getScheduler(StdSchedulerFactory.java:1519)
    at com.example.singleQuartz.SingleQuartzKeepAlive.main(SingleQuartzKeepAlive.java:17)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
    at java.lang.reflect.Method.invoke(Unknown Source)
    at com.intellij.rt.execution.application.AppMain.main(AppMain.java:144)
Caused by: java.lang.ClassNotFoundException: com.mchange.v2.c3p0.ComboPooledDataSource
    at java.net.URLClassLoader.findClass(Unknown Source)
    at java.lang.ClassLoader.loadClass(Unknown Source)
    at sun.misc.Launcher$AppClassLoader.loadClass(Unknown Source)
    at java.lang.ClassLoader.loadClass(Unknown Source)
    ... 10 more

Process finished with exit code 1

 运行结果正常,我们在数据库可以看到 job 和 trigger 表都有了任务调度记录数据。此时我们不妨只启动原来的调度器,看看是否任务调度还能正常进行。通过结果同学们就很清楚了,这次任务调度我们只执行了 4 次,因为在程序中断之前运行了 7 次。

package com.example.singleQuartz;

import org.quartz.Scheduler;
import org.quartz.SchedulerException;
import org.quartz.impl.StdSchedulerFactory;

import java.util.concurrent.TimeUnit;

/**
 * Created by XuHui on 2016/12/23.
 */
public class SingleQuartzOldScheduler {public static void main(String[] args) throws SchedulerException {StdSchedulerFactory factory = new StdSchedulerFactory();
        factory.initialize("quartz.properities");
        Scheduler scheduler = factory.getScheduler();
        scheduler.start();
        try{TimeUnit.MINUTES.sleep(1);
        } catch (Exception e) {e.printStackTrace();
        } finally {scheduler.shutdown();
        }
    }
}
================= 结果 ====================
[main] INFO org.quartz.core.QuartzScheduler - Scheduler MyScheduler_$_NON_CLUSTERED started.
Hello, Quartz! - executing its JOB at Fri Dec 23 09:20:16 CST 2016 by DEFAULT.job
Hello, Quartz! - executing its JOB at Fri Dec 23 09:20:26 CST 2016 by DEFAULT.job
Hello, Quartz! - executing its JOB at Fri Dec 23 09:20:36 CST 2016 by DEFAULT.job
Hello, Quartz! - executing its JOB at Fri Dec 23 09:20:46 CST 2016 by DEFAULT.job
[main] INFO org.quartz.core.QuartzScheduler - Scheduler MyScheduler_$_NON_CLUSTERED shutting down.
[main] INFO org.quartz.core.QuartzScheduler - Scheduler MyScheduler_$_NON_CLUSTERED paused.
[main] INFO org.quartz.core.QuartzScheduler - Scheduler MyScheduler_$_NON_CLUSTERED shutdown complete.

5. 最终的工程目录结构

Quartz2.0 以上版本的单机和集群

(三)Quartz 集群

1. 搭建 web 工程

看完第二部分之后,大部分同学已经明白了,Quartz 集群是怎么回事了。其实就是把调度任务存到数据库中,集群的时候每台服务器调度任务都指向同一数据库,从同一数据库取调度任务,这就是 Quartz 集群了。为在本地验证 quartz 集群,我重新搭建一个工程,里面撘两个 web 模块,目录结构如下。clusterweb_two 和 clusterweb_one 文件和配置一模一样。

Quartz2.0 以上版本的单机和集群

2. 配置 Quartz 集群文件 quartz.properities

多台服务器上的这个配置文件除了 instanceId 不同,这里可以设置成 AUTO 根据机器自动生成,其他基本都相同,必须限定的是数据库信息必须相同。

org.quartz.scheduler.instanceName = ClusterScheduler
org.quartz.threadPool.threadCount = 3
org.quartz.jobStore.class = org.quartz.impl.jdbcjobstore.JobStoreTX
org.quartz.jobStore.driverDelegateClass = org.quartz.impl.jdbcjobstore.StdJDBCDelegate
org.quartz.jobStore.tablePrefix = QRTZ_
org.quartz.jobStore.dataSource = myDS
# Cluster
org.quartz.jobStore.isClustered = true
org.quartz.scheduler.instanceId = AUTO

org.quartz.dataSource.myDS.driver = com.mysql.jdbc.Driver
org.quartz.dataSource.myDS.URL = jdbc:mysql://localhost:3306/quartz?characterEncoding=utf-8
org.quartz.dataSource.myDS.user = root
org.quartz.dataSource.myDS.password = 123456
org.quartz.dataSource.myDS.maxConnections = 5

3. 配置 web 监听器

我们把调度器放到 web 监听器中运行,当 web 启动时会运行这个监听器,同时会启动调度器,监听器 QuartzApplicationListener.java 如下所示。

package com.example.web;

import org.quartz.*;
import org.quartz.impl.StdSchedulerFactory;

import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
import java.util.Date;
import java.util.concurrent.TimeUnit;

/**
 * Created by XuHui on 2016/12/23.
 */
public class QuartzApplicationListener implements ServletContextListener {private Scheduler scheduler = null;
    @Override
    public void contextInitialized(ServletContextEvent servletContextEvent) {StdSchedulerFactory factory = new StdSchedulerFactory();
        try {factory.initialize("quartz.properities");
            scheduler = factory.getScheduler();
             /* 启动调度器 */
            scheduler.start();} catch (SchedulerException e) {e.printStackTrace();
        }

        JobDetail jobDetail = JobBuilder.newJob(HelloJob.class)
                .withIdentity("job", Scheduler.DEFAULT_GROUP)
                .build();

        Date startTime = DateBuilder.nextGivenSecondDate(null, 30);
        SimpleTrigger simpleTrigger = TriggerBuilder.newTrigger()
                .withIdentity("trigger", Scheduler.DEFAULT_GROUP)
                .startAt(startTime)
                .withSchedule(SimpleScheduleBuilder.simpleSchedule()
                        .withIntervalInSeconds(10)
                        .withRepeatCount(10))
                .forJob(jobDetail)
                .build();
        try{/* 交由调度器调度 Job */
            scheduler.scheduleJob(jobDetail, simpleTrigger);
        } catch (SchedulerException e) {e.printStackTrace();
        }

        /* 3 分钟任务调度之后关闭调度器 */
        try{TimeUnit.MINUTES.sleep(3);
        }catch (Exception e) {e.printStackTrace();
        }

    }

    @Override
    public void contextDestroyed(ServletContextEvent servletContextEvent) {try{scheduler.shutdown();
        } catch (SchedulerException e) {e.printStackTrace();
        }
    }
}

4.web 配置文件 web.xml

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
         version="3.1">
    <listener>
        <listener-class>
            com.example.web.QuartzApplicationListener
        </listener-class>
    </listener>
</web-app>

5. 运行两个 tomcat 模拟集群

在 idea 中配置两个 tomcat,并且让两个 tomcat 同时运行有点小麻烦,主要注意一点每个 tomcat 配置的 Http Port 和 JMX Port 要不同。

tomcat1 : Http Port : 8081 JMX Port : 1099

tomcat2 : Http Port : 8082 JMX Port : 1100

tomcat1 和 tomcat2 运行成功之后,此时两个服务都已启动,此时只有 tomcat1 开始任务调度,tomcat2 未进行任务调度。首先把 tomcat1 服务停掉,此时会出现 tomcat2 任务调度开始,这里跟做服务高可靠性很像。运行结果:

==============tomcat1=====================
Hello, Quartz! - executing its JOB at Fri Dec 23 11:27:00 CST 2016 by DEFAULT.job on webone
Hello, Quartz! - executing its JOB at Fri Dec 23 11:27:10 CST 2016 by DEFAULT.job on webone
Hello, Quartz! - executing its JOB at Fri Dec 23 11:27:20 CST 2016 by DEFAULT.job on webone
Hello, Quartz! - executing its JOB at Fri Dec 23 11:27:30 CST 2016 by DEFAULT.job on webone
D:\work\tomcat\apache-tomcat-8.0.23-windows-x64\apache-tomcat-8.0.23\bin\catalina.bat stop
Disconnected from server
==============tomcat2=====================
Hello, Quartz! - executing its JOB at Fri Dec 23 11:27:56 CST 2016 by DEFAULT.job on webtwo
Hello, Quartz! - executing its JOB at Fri Dec 23 11:27:56 CST 2016 by DEFAULT.job on webtwo
Hello, Quartz! - executing its JOB at Fri Dec 23 11:28:00 CST 2016 by DEFAULT.job on webtwo
Hello, Quartz! - executing its JOB at Fri Dec 23 11:28:10 CST 2016 by DEFAULT.job on webtwo
Hello, Quartz! - executing its JOB at Fri Dec 23 11:28:20 CST 2016 by DEFAULT.job on webtwo
Hello, Quartz! - executing its JOB at Fri Dec 23 11:28:30 CST 2016 by DEFAULT.job on webtwo
Hello, Quartz! - executing its JOB at Fri Dec 23 11:28:40 CST 2016 by DEFAULT.job on webtwo
[2016-12-23 11:29:48,369] Artifact clusterweb_two:war exploded: Artifact is deployed successfully

写在最后Quartz 基础部分总结起来可能不多,实际应用主要是 Job 中 execute 方法的实现。看完上面的介绍之后我们发现,Quartz 使用起来非常方便,Quartz 提供了很多日期和日历类。写过定时备份、定时查询统计方法的同学,知道这里写起来很麻烦。Quqatz 大大缩减了程序的代码量。之前和一位同事讨论了什么时候用 Quartz,很多时候我们都会自己写任务调度。一般都是这样实现的:我们会启线程相当于定时器,定时去查询符合条件的 Job,如果查询到多 Job 同时调度,我们会启一个线程池多线程并发运行。这样看上去 Quartz 都具备了,使用 Quartz 之后代码非常简洁、可复用性高并且任务调度的可持久性,只需要配置 Quartz 配置文件就可以将调度任务存到数据库中,正是因为这点所以 Quartz 可以集群,对于任务数很多的集群环境下,这就是无与伦比的优点了。如果在搭建环境或者发现文章中有不对或不足的地方,可以在下方留言,大家共同学习。

本文永久更新链接地址:http://www.linuxidc.com/Linux/2016-12/138743.htm

(一)Quartz 单机

1.Quartz 简介

Quartz 是一个完全由 java 编写的开源作业调度框架,能实现业务的定时调度。Quartz 主要有三个核心调度器、任务和触发器:

①任务 -JobDetail:Quartz 在任务调度的时候,需要创建一个任务实例,JobDetail 正是承担这个角色。在 Quartz2.0 以前的版本中,创建一个任务通过 new JobDetail(String jobName, String gruop, Class jobCLass)这个方法来创建,在 2.0 之后的版本中通过 JobBuilder 来创建任务。Job 接口中只有一个方法 void execute(JobExecutionContext context) throws JobExecutionException,因此在任务调度时,只需要实现 execute 方法就可以了,使用起来很方便。

②触发器 -Trigger:定义 Job 的执行时间、次数等信息,有 SimpleTrigger 和 CronTrigger 两种类型。当你需要的是一次性的调度,或者你需要在指定的时间激活某个任务并执行 N 次,设置每次任务执行的间隔时间 T。那此时使用 SimpleTrigger 将是非常方便的。如果你想在每周的周一 7:00 或者每月的第 2,3 天实现任务调度,这时候就需要用到 CronTrigger,CronTrigger 能够提供复杂的触发器表达式满足我们的需求。同时需要提到的一点是 Quartz 还提供很多日期的实现类 DateBuilder 等,在实际使用中很方便。

③调度器 -Scheduler:Quartz 框架的核心是调度器。调度器负责管理 Quartz 应用运行时环境。调度器不是靠自己做所有的工作,而是依赖框架内一些非常重要的部件。Quartz 不仅仅是线程和线程管理。为确保可伸缩性,Quartz 采用了基于多线程的架构。启动时,框架初始化一套 worker 线程,这套线程被调度器用来执行预定的作业。这就是 Quartz 怎样能并发运行多个作业的原理。Quartz 依赖一套松耦合的线程池管理部件来管理线程环境。

Spring3.2.11 与 Quartz2.2.1 整合时内存泄漏问题解决  http://www.linuxidc.com/Linux/2015-06/119042.htm

Spring 配置 Quartz 任务调度框架教程  http://www.linuxidc.com/Linux/2014-11/108907.htm

Quartz 深入浅出 http://www.linuxidc.com/Linux/2014-09/107007.htm

Quartz1.6 有状态 JOB 碰到的棘手问题既解决方案 http://www.linuxidc.com/Linux/2014-09/107005.htm

Spring 3 整合 Quartz 2 实现定时任务 http://www.linuxidc.com/Linux/2014-09/107006.htm

Java 项目中定时任务之 Quartz 的应用 http://www.linuxidc.com/Linux/2013-12/94443.htm

Spring 3 调度器示例 —— JDK 定时器和 Quartz 展示 http://www.linuxidc.com/Linux/2013-10/91946.htm

Quartz 框架 实现任务调度 http://www.linuxidc.com/Linux/2016-11/136778.htm

Spring Quartz 定时任务 http://www.linuxidc.com/Linux/2016-11/137525.htm

2. 搭建 Quartz 工程

①创建一个新工程

新建文件 lib 作为外部 jar 包,Quartz 最新版本通过官网可以下载 http://www.quartz-scheduler.org/downloads/。 导入你下载的 quartz 包,新建 package 为 com.example.singleQuartz, 里面就两个简单的类 SingleQuartzJob 和 SingleQuartzServer。SingleQuartzJob 定义 Job 的实现类,SingleQuartzServer 任务调度服务。

Quartz2.0 以上版本的单机和集群

②SingleQuartzJob.java 定义 Job 的实现类

package com.example.singleQuartz;

import org.quartz.Job;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;

import java.util.Date;

/**
 * Created by XuHui on 2016/12/22.
 */
public class SingleQuartzJob implements Job {
    @Override
    public void execute(JobExecutionContext context) throws JobExecutionException {System.out.print("Hello, Quartz! - executing its JOB at"+
                new Date() + "by" + context.getTrigger().getJobKey() + "\n");
    }
}

③SingleQuartzServer.java 实现任务调度

package com.example.singleQuartz;

import org.quartz.*;
import org.quartz.impl.StdSchedulerFactory;

import java.util.Date;
import java.util.concurrent.TimeUnit;

/**
 * Created by XuHui on 2016/12/22.
 */
public class SingleQuartzServer {public static void main(String[] args) throws SchedulerException {/* 获取 Scheduler 实例 */
        SchedulerFactory factory = new StdSchedulerFactory();
        Scheduler scheduler = factory.getScheduler();

        /* 启动调度器 */
        scheduler.start();

        /* 任务:withIdentity(String name, String group),其中 groupName 可以自己定义,也可以用 Scheduler 提供的 DEFAULT_GROUP。这里要求同组里面的 jobName 不能相同*/
        JobDetail jobDetail = JobBuilder.newJob(SingleQuartzJob.class)
                .withIdentity("job", Scheduler.DEFAULT_GROUP)
                .build();

        /*触发器:SimpleTrigger 和 CronTrigger。实现的功能是:接下来 30s 后执行 job,以后每个 10s 执行一次,重复 10 次,一共执行 11 次。nextGivenSecondDate(null, 30)距离现在时间 30s 之后执行 job,此处 null 可写作 new Date(), 可自行在 api 查看源码实现 */
        Date startTime = DateBuilder.nextGivenSecondDate(null, 30);
        SimpleTrigger simpleTrigger = TriggerBuilder.newTrigger()
                .withIdentity("trigger", Scheduler.DEFAULT_GROUP)
                .startAt(startTime)
                .withSchedule(SimpleScheduleBuilder.simpleSchedule()
                        .withIntervalInSeconds(10)
                        .withRepeatCount(10))
                .forJob(jobDetail)
                .build();

        /* 交由调度器调度 Job */
        scheduler.scheduleJob(jobDetail, simpleTrigger);

        /* 3 分钟任务调度之后关闭调度器 */
        try{TimeUnit.MINUTES.sleep(3);
        } catch (Exception e) {e.printStackTrace();
        } finally {scheduler.shutdown();
        }
    }
}

④执行任务调度

执行 run->main 但是发现报错了。此时是少了两个个日志包,slf4j-api-1.7.22.jar 和 slf4j-simple-1.7.22.jar,我们只要添加 slf4j 包就可以了。

通过官网可以下载http://www.slf4j.org/download.html,找到这两个包放到 lib 下就可以了。

Exception in thread "main" java.lang.NoClassDefFoundError: org/slf4j/LoggerFactory
    at org.quartz.impl.StdSchedulerFactory.<init>(StdSchedulerFactory.java:303)
    at com.example.singleQuartz.SingleQuartzServer.main(SingleQuartzServer.java:15)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
    at java.lang.reflect.Method.invoke(Unknown Source)
    at com.intellij.rt.execution.application.AppMain.main(AppMain.java:144)
Caused by: java.lang.ClassNotFoundException: org.slf4j.LoggerFactory
    at java.net.URLClassLoader.findClass(Unknown Source)
    at java.lang.ClassLoader.loadClass(Unknown Source)
    at sun.misc.Launcher$AppClassLoader.loadClass(Unknown Source)
    at java.lang.ClassLoader.loadClass(Unknown Source)
    ... 7 more

解决完上面日志包的问题,我们运行上面程序可以看到正常的调度结果如下。


[main] INFO org.quartz.core.QuartzScheduler - Scheduler DefaultQuartzScheduler_$_NON_CLUSTERED started.
Hello, Quartz! - executing its JOB at Thu Dec 22 19:40:30 CST 2016 by DEFAULT.job
Hello, Quartz! - executing its JOB at Thu Dec 22 19:40:40 CST 2016 by DEFAULT.job
Hello, Quartz! - executing its JOB at Thu Dec 22 19:40:50 CST 2016 by DEFAULT.job
Hello, Quartz! - executing its JOB at Thu Dec 22 19:41:00 CST 2016 by DEFAULT.job
Hello, Quartz! - executing its JOB at Thu Dec 22 19:41:10 CST 2016 by DEFAULT.job
Hello, Quartz! - executing its JOB at Thu Dec 22 19:41:20 CST 2016 by DEFAULT.job
Hello, Quartz! - executing its JOB at Thu Dec 22 19:41:30 CST 2016 by DEFAULT.job
Hello, Quartz! - executing its JOB at Thu Dec 22 19:41:40 CST 2016 by DEFAULT.job
Hello, Quartz! - executing its JOB at Thu Dec 22 19:41:50 CST 2016 by DEFAULT.job
Hello, Quartz! - executing its JOB at Thu Dec 22 19:42:00 CST 2016 by DEFAULT.job
Hello, Quartz! - executing its JOB at Thu Dec 22 19:42:10 CST 2016 by DEFAULT.job
[main] INFO org.quartz.core.QuartzScheduler - Scheduler DefaultQuartzScheduler_$_NON_CLUSTERED shutting down.
[main] INFO org.quartz.core.QuartzScheduler - Scheduler DefaultQuartzScheduler_$_NON_CLUSTERED paused.
[main] INFO org.quartz.core.QuartzScheduler - Scheduler DefaultQuartzScheduler_$_NON_CLUSTERED shutdown complete.

 ⑤任务调度的多线程

Scheduler 是存在多对多的关系,由于线程池的存在,调度器实现多线程并发执行任务调度,直接看下面 demo 就能明白。

package com.example.singleQuartz;

import org.quartz.*;
import org.quartz.impl.StdSchedulerFactory;

import java.util.Date;
import java.util.concurrent.TimeUnit;

/**
 * Created by XuHui on 2016/12/22.
 */
public class SingleQuartzThreadPoolServer {public static void main(String[] args) throws SchedulerException {/* 获取 Scheduler 实例 */
        SchedulerFactory factory = new StdSchedulerFactory();
        Scheduler scheduler = factory.getScheduler();

        /* 启动调度器 */
        scheduler.start();

        /******************************************************* Job-1 ****************************************************************/
        /* 任务:withIdentity(String name, String group),其中 groupName 可以自己定义,也可以用 Scheduler 提供的 DEFAULT_GROUP。这里要求同组里面的 jobName 不能相同*/
        JobDetail jobDetail = JobBuilder.newJob(SingleQuartzJob.class)
                .withIdentity("job1", Scheduler.DEFAULT_GROUP)
                .build();

        /*触发器:SimpleTrigger 和 CronTrigger。实现的功能是:接下来 30s 后执行 job,以后每个 10s 执行一次,重复 10 次,一共执行 11 次。nextGivenSecondDate(null, 30)距离现在时间 30s 之后执行 job,此处 null 可写作 new Date(), 可自行在 api 查看源码实现 */
        Date startTime = DateBuilder.nextGivenSecondDate(null, 30);
        SimpleTrigger simpleTrigger = TriggerBuilder.newTrigger()
                .withIdentity("trigger1", Scheduler.DEFAULT_GROUP)
                .startAt(startTime)
                .withSchedule(SimpleScheduleBuilder.simpleSchedule()
                        .withIntervalInSeconds(10)
                        .withRepeatCount(2))
                .forJob(jobDetail)
                .build();

        /* 交由调度器调度 Job */
        scheduler.scheduleJob(jobDetail, simpleTrigger);

        /******************************************************* Job-2 ****************************************************************/
        jobDetail = JobBuilder.newJob(SingleQuartzJob.class)
                .withIdentity("job2", Scheduler.DEFAULT_GROUP)
                .build();

        simpleTrigger = TriggerBuilder.newTrigger()
                .withIdentity("trigger2", Scheduler.DEFAULT_GROUP)
                .startAt(startTime)
                .withSchedule(SimpleScheduleBuilder.simpleSchedule()
                        .withIntervalInSeconds(10)
                        .withRepeatCount(2))
                .forJob(jobDetail)
                .build();
        scheduler.scheduleJob(jobDetail, simpleTrigger);

        /******************************************************* Job-3 ****************************************************************/
        jobDetail = JobBuilder.newJob(SingleQuartzJob.class)
                .withIdentity("job3", Scheduler.DEFAULT_GROUP)
                .build();

        simpleTrigger = TriggerBuilder.newTrigger()
                .withIdentity("trigger3", Scheduler.DEFAULT_GROUP)
                .startAt(startTime)
                .withSchedule(SimpleScheduleBuilder.simpleSchedule()
                        .withIntervalInSeconds(10)
                        .withRepeatCount(2))
                .forJob(jobDetail)
                .build();
        scheduler.scheduleJob(jobDetail, simpleTrigger);

        /* 2 分钟任务调度之后关闭调度器 */
        try{TimeUnit.MINUTES.sleep(2);
        } catch (Exception e) {e.printStackTrace();
        } finally {scheduler.shutdown();
        }
    }

}

执行结果如下:

[main] INFO org.quartz.core.QuartzScheduler - Scheduler DefaultQuartzScheduler_$_NON_CLUSTERED started.
Hello, Quartz! - executing its JOB at Thu Dec 22 19:52:30 CST 2016 by DEFAULT.job1
Hello, Quartz! - executing its JOB at Thu Dec 22 19:52:30 CST 2016 by DEFAULT.job2
Hello, Quartz! - executing its JOB at Thu Dec 22 19:52:30 CST 2016 by DEFAULT.job3
Hello, Quartz! - executing its JOB at Thu Dec 22 19:52:40 CST 2016 by DEFAULT.job3
Hello, Quartz! - executing its JOB at Thu Dec 22 19:52:40 CST 2016 by DEFAULT.job1
Hello, Quartz! - executing its JOB at Thu Dec 22 19:52:40 CST 2016 by DEFAULT.job2
Hello, Quartz! - executing its JOB at Thu Dec 22 19:52:50 CST 2016 by DEFAULT.job1
Hello, Quartz! - executing its JOB at Thu Dec 22 19:52:50 CST 2016 by DEFAULT.job3
Hello, Quartz! - executing its JOB at Thu Dec 22 19:52:50 CST 2016 by DEFAULT.job2
[main] INFO org.quartz.core.QuartzScheduler - Scheduler DefaultQuartzScheduler_$_NON_CLUSTERED shutting down.
[main] INFO org.quartz.core.QuartzScheduler - Scheduler DefaultQuartzScheduler_$_NON_CLUSTERED paused.
[main] INFO org.quartz.core.QuartzScheduler - Scheduler DefaultQuartzScheduler_$_NON_CLUSTERED shutdown complete.

 (二)任务调度持久到数据库

1. 建立数据库和建表

上面的例子的任务是存在内存中的,如果程序关闭任务就会消失,为了保持任务的可持久性,需要将任务调度存到数据库中。在你下载的 quartz 包下找到 quartz-2.2.1\docs\dbTables\,找到你对应的数据库建表语言,这里我用的是 mysql 数据库 tables_mysql.sql。在你本地或者服务器数据库新建一个数据库 quartz(你可以不建,主要为了和其他数据库区分)。将以下的建表语言导入该数据库。

#
# Quartz seems to work best with the driver mm.mysql-2.0.7-bin.jar
#
# PLEASE consider using mysql with innodb tables to avoid locking issues
#
# In your Quartz properties file, you'll need to set 
# org.quartz.jobStore.driverDelegateClass = org.quartz.impl.jdbcjobstore.StdJDBCDelegate
#

DROP TABLE IF EXISTS QRTZ_FIRED_TRIGGERS;
DROP TABLE IF EXISTS QRTZ_PAUSED_TRIGGER_GRPS;
DROP TABLE IF EXISTS QRTZ_SCHEDULER_STATE;
DROP TABLE IF EXISTS QRTZ_LOCKS;
DROP TABLE IF EXISTS QRTZ_SIMPLE_TRIGGERS;
DROP TABLE IF EXISTS QRTZ_SIMPROP_TRIGGERS;
DROP TABLE IF EXISTS QRTZ_CRON_TRIGGERS;
DROP TABLE IF EXISTS QRTZ_BLOB_TRIGGERS;
DROP TABLE IF EXISTS QRTZ_TRIGGERS;
DROP TABLE IF EXISTS QRTZ_JOB_DETAILS;
DROP TABLE IF EXISTS QRTZ_CALENDARS;


CREATE TABLE QRTZ_JOB_DETAILS
  (SCHED_NAME VARCHAR(120) NOT NULL,
    JOB_NAME  VARCHAR(200) NOT NULL,
    JOB_GROUP VARCHAR(200) NOT NULL,
    DESCRIPTION VARCHAR(250) NULL,
    JOB_CLASS_NAME   VARCHAR(250) NOT NULL,
    IS_DURABLE VARCHAR(1) NOT NULL,
    IS_NONCONCURRENT VARCHAR(1) NOT NULL,
    IS_UPDATE_DATA VARCHAR(1) NOT NULL,
    REQUESTS_RECOVERY VARCHAR(1) NOT NULL,
    JOB_DATA BLOB NULL,
    PRIMARY KEY (SCHED_NAME,JOB_NAME,JOB_GROUP)
);

CREATE TABLE QRTZ_TRIGGERS
  (SCHED_NAME VARCHAR(120) NOT NULL,
    TRIGGER_NAME VARCHAR(200) NOT NULL,
    TRIGGER_GROUP VARCHAR(200) NOT NULL,
    JOB_NAME  VARCHAR(200) NOT NULL,
    JOB_GROUP VARCHAR(200) NOT NULL,
    DESCRIPTION VARCHAR(250) NULL,
    NEXT_FIRE_TIME BIGINT(13) NULL,
    PREV_FIRE_TIME BIGINT(13) NULL,
    PRIORITY INTEGER NULL,
    TRIGGER_STATE VARCHAR(16) NOT NULL,
    TRIGGER_TYPE VARCHAR(8) NOT NULL,
    START_TIME BIGINT(13) NOT NULL,
    END_TIME BIGINT(13) NULL,
    CALENDAR_NAME VARCHAR(200) NULL,
    MISFIRE_INSTR SMALLINT(2) NULL,
    JOB_DATA BLOB NULL,
    PRIMARY KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP),
    FOREIGN KEY (SCHED_NAME,JOB_NAME,JOB_GROUP)
        REFERENCES QRTZ_JOB_DETAILS(SCHED_NAME,JOB_NAME,JOB_GROUP)
);

CREATE TABLE QRTZ_SIMPLE_TRIGGERS
  (SCHED_NAME VARCHAR(120) NOT NULL,
    TRIGGER_NAME VARCHAR(200) NOT NULL,
    TRIGGER_GROUP VARCHAR(200) NOT NULL,
    REPEAT_COUNT BIGINT(7) NOT NULL,
    REPEAT_INTERVAL BIGINT(12) NOT NULL,
    TIMES_TRIGGERED BIGINT(10) NOT NULL,
    PRIMARY KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP),
    FOREIGN KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP)
        REFERENCES QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP)
);

CREATE TABLE QRTZ_CRON_TRIGGERS
  (SCHED_NAME VARCHAR(120) NOT NULL,
    TRIGGER_NAME VARCHAR(200) NOT NULL,
    TRIGGER_GROUP VARCHAR(200) NOT NULL,
    CRON_EXPRESSION VARCHAR(200) NOT NULL,
    TIME_ZONE_ID VARCHAR(80),
    PRIMARY KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP),
    FOREIGN KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP)
        REFERENCES QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP)
);

CREATE TABLE QRTZ_SIMPROP_TRIGGERS
  (SCHED_NAME VARCHAR(120) NOT NULL,
    TRIGGER_NAME VARCHAR(200) NOT NULL,
    TRIGGER_GROUP VARCHAR(200) NOT NULL,
    STR_PROP_1 VARCHAR(512) NULL,
    STR_PROP_2 VARCHAR(512) NULL,
    STR_PROP_3 VARCHAR(512) NULL,
    INT_PROP_1 INT NULL,
    INT_PROP_2 INT NULL,
    LONG_PROP_1 BIGINT NULL,
    LONG_PROP_2 BIGINT NULL,
    DEC_PROP_1 NUMERIC(13,4) NULL,
    DEC_PROP_2 NUMERIC(13,4) NULL,
    BOOL_PROP_1 VARCHAR(1) NULL,
    BOOL_PROP_2 VARCHAR(1) NULL,
    PRIMARY KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP),
    FOREIGN KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP) 
    REFERENCES QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP)
);

CREATE TABLE QRTZ_BLOB_TRIGGERS
  (SCHED_NAME VARCHAR(120) NOT NULL,
    TRIGGER_NAME VARCHAR(200) NOT NULL,
    TRIGGER_GROUP VARCHAR(200) NOT NULL,
    BLOB_DATA BLOB NULL,
    PRIMARY KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP),
    FOREIGN KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP)
        REFERENCES QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP)
);

CREATE TABLE QRTZ_CALENDARS
  (SCHED_NAME VARCHAR(120) NOT NULL,
    CALENDAR_NAME  VARCHAR(200) NOT NULL,
    CALENDAR BLOB NOT NULL,
    PRIMARY KEY (SCHED_NAME,CALENDAR_NAME)
);

CREATE TABLE QRTZ_PAUSED_TRIGGER_GRPS
  (SCHED_NAME VARCHAR(120) NOT NULL,
    TRIGGER_GROUP  VARCHAR(200) NOT NULL, 
    PRIMARY KEY (SCHED_NAME,TRIGGER_GROUP)
);

CREATE TABLE QRTZ_FIRED_TRIGGERS
  (SCHED_NAME VARCHAR(120) NOT NULL,
    ENTRY_ID VARCHAR(95) NOT NULL,
    TRIGGER_NAME VARCHAR(200) NOT NULL,
    TRIGGER_GROUP VARCHAR(200) NOT NULL,
    INSTANCE_NAME VARCHAR(200) NOT NULL,
    FIRED_TIME BIGINT(13) NOT NULL,
    SCHED_TIME BIGINT(13) NOT NULL,
    PRIORITY INTEGER NOT NULL,
    STATE VARCHAR(16) NOT NULL,
    JOB_NAME VARCHAR(200) NULL,
    JOB_GROUP VARCHAR(200) NULL,
    IS_NONCONCURRENT VARCHAR(1) NULL,
    REQUESTS_RECOVERY VARCHAR(1) NULL,
    PRIMARY KEY (SCHED_NAME,ENTRY_ID)
);

CREATE TABLE QRTZ_SCHEDULER_STATE
  (SCHED_NAME VARCHAR(120) NOT NULL,
    INSTANCE_NAME VARCHAR(200) NOT NULL,
    LAST_CHECKIN_TIME BIGINT(13) NOT NULL,
    CHECKIN_INTERVAL BIGINT(13) NOT NULL,
    PRIMARY KEY (SCHED_NAME,INSTANCE_NAME)
);

CREATE TABLE QRTZ_LOCKS
  (SCHED_NAME VARCHAR(120) NOT NULL,
    LOCK_NAME  VARCHAR(40) NOT NULL, 
    PRIMARY KEY (SCHED_NAME,LOCK_NAME)
);


commit;

2. 导入 mysql 数据库的 jdbc 驱动包,mysql-connector-java-5.1.40-bin.jar

更多详情见请继续阅读下一页的精彩内容:http://www.linuxidc.com/Linux/2016-12/138743p2.htm

正文完
星哥玩云-微信公众号
post-qrcode
 0
星锅
版权声明:本站原创文章,由 星锅 于2022-01-21发表,共计36685字。
转载说明:除特殊说明外本站文章皆由CC-4.0协议发布,转载请注明出处。
【腾讯云】推广者专属福利,新客户无门槛领取总价值高达2860元代金券,每种代金券限量500张,先到先得。
阿里云-最新活动爆款每日限量供应
评论(没有评论)
验证码
【腾讯云】云服务器、云数据库、COS、CDN、短信等云产品特惠热卖中

星哥玩云

星哥玩云
星哥玩云
分享互联网知识
用户数
4
文章数
19351
评论数
4
阅读量
7981234
文章搜索
热门文章
星哥带你玩飞牛NAS-6:抖音视频同步工具,视频下载自动下载保存

星哥带你玩飞牛NAS-6:抖音视频同步工具,视频下载自动下载保存

星哥带你玩飞牛 NAS-6:抖音视频同步工具,视频下载自动下载保存 前言 各位玩 NAS 的朋友好,我是星哥!...
星哥带你玩飞牛NAS-3:安装飞牛NAS后的很有必要的操作

星哥带你玩飞牛NAS-3:安装飞牛NAS后的很有必要的操作

星哥带你玩飞牛 NAS-3:安装飞牛 NAS 后的很有必要的操作 前言 如果你已经有了飞牛 NAS 系统,之前...
我把用了20年的360安全卫士卸载了

我把用了20年的360安全卫士卸载了

我把用了 20 年的 360 安全卫士卸载了 是的,正如标题你看到的。 原因 偷摸安装自家的软件 莫名其妙安装...
再见zabbix!轻量级自建服务器监控神器在Linux 的完整部署指南

再见zabbix!轻量级自建服务器监控神器在Linux 的完整部署指南

再见 zabbix!轻量级自建服务器监控神器在 Linux 的完整部署指南 在日常运维中,服务器监控是绕不开的...
飞牛NAS中安装Navidrome音乐文件中文标签乱码问题解决、安装FntermX终端

飞牛NAS中安装Navidrome音乐文件中文标签乱码问题解决、安装FntermX终端

飞牛 NAS 中安装 Navidrome 音乐文件中文标签乱码问题解决、安装 FntermX 终端 问题背景 ...
阿里云CDN
阿里云CDN-提高用户访问的响应速度和成功率
随机文章
240 元左右!五盘位 NAS主机,7 代U硬解4K稳如狗,拓展性碾压同价位

240 元左右!五盘位 NAS主机,7 代U硬解4K稳如狗,拓展性碾压同价位

  240 元左右!五盘位 NAS 主机,7 代 U 硬解 4K 稳如狗,拓展性碾压同价位 在 NA...
手把手教你,购买云服务器并且安装宝塔面板

手把手教你,购买云服务器并且安装宝塔面板

手把手教你,购买云服务器并且安装宝塔面板 前言 大家好,我是星哥。星哥发现很多新手刚接触服务器时,都会被“选购...
国产开源公众号AI知识库 Agent:突破未认证号限制,一键搞定自动回复,重构运营效率

国产开源公众号AI知识库 Agent:突破未认证号限制,一键搞定自动回复,重构运营效率

国产开源公众号 AI 知识库 Agent:突破未认证号限制,一键搞定自动回复,重构运营效率 大家好,我是星哥,...
颠覆 AI 开发效率!开源工具一站式管控 30+大模型ApiKey,秘钥付费+负载均衡全搞定

颠覆 AI 开发效率!开源工具一站式管控 30+大模型ApiKey,秘钥付费+负载均衡全搞定

  颠覆 AI 开发效率!开源工具一站式管控 30+ 大模型 ApiKey,秘钥付费 + 负载均衡全...
星哥带你玩飞牛NAS-2:飞牛配置RAID磁盘阵列

星哥带你玩飞牛NAS-2:飞牛配置RAID磁盘阵列

星哥带你玩飞牛 NAS-2:飞牛配置 RAID 磁盘阵列 前言 大家好,我是星哥之前星哥写了《星哥带你玩飞牛 ...

免费图片视频管理工具让灵感库告别混乱

一言一句话
-「
手气不错
4盘位、4K输出、J3455、遥控,NAS硬件入门性价比之王

4盘位、4K输出、J3455、遥控,NAS硬件入门性价比之王

  4 盘位、4K 输出、J3455、遥控,NAS 硬件入门性价比之王 开篇 在 NAS 市场中,威...
国产开源公众号AI知识库 Agent:突破未认证号限制,一键搞定自动回复,重构运营效率

国产开源公众号AI知识库 Agent:突破未认证号限制,一键搞定自动回复,重构运营效率

国产开源公众号 AI 知识库 Agent:突破未认证号限制,一键搞定自动回复,重构运营效率 大家好,我是星哥,...
免费无广告!这款跨平台AI RSS阅读器,拯救你的信息焦虑

免费无广告!这款跨平台AI RSS阅读器,拯救你的信息焦虑

  免费无广告!这款跨平台 AI RSS 阅读器,拯救你的信息焦虑 在算法推荐主导信息流的时代,我们...
自己手撸一个AI智能体—跟创业大佬对话

自己手撸一个AI智能体—跟创业大佬对话

自己手撸一个 AI 智能体 — 跟创业大佬对话 前言 智能体(Agent)已经成为创业者和技术人绕...
开源MoneyPrinterTurbo 利用AI大模型,一键生成高清短视频!

开源MoneyPrinterTurbo 利用AI大模型,一键生成高清短视频!

  开源 MoneyPrinterTurbo 利用 AI 大模型,一键生成高清短视频! 在短视频内容...