spring 配置动态quartz任务调度

quartz是任务调用框架,和数据库交互实现动态调度任务。可以集群模式,集群在于更加可靠,如果一个节点在执行时间没有调用,在有其它相同配置的集群内其它配置的机器会同样调度,同时它会检查状态,保证同一个任务只会在需要被调用的时间只调用一次。

优势在于动态,可以在执行时暂停或者删除任务。

maven项目实现

spring版本:4.3.18

quartz:2.2.3

maven依赖:

<dependency>

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

<artifactId>quartz</artifactId>

<version>2.2.3</version>

</dependency>

<dependency>

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

<artifactId>quartz-jobs</artifactId>

<version>2.2.3</version>

</dependency>

这次配置的quartz是基于数据库的表配置的,需要用到一些表:

基于mysql的建表语句:

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

ENGINE=InnoDB;  


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

ENGINE=InnoDB;  


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

ENGINE=InnoDB;  


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

ENGINE=InnoDB;  


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

ENGINE=InnoDB;  


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),  

INDEX (SCHED_NAME,TRIGGER_NAME, TRIGGER_GROUP),  

FOREIGN KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP)  

REFERENCES QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP))  

ENGINE=InnoDB;  


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

ENGINE=InnoDB;  


CREATE TABLE QRTZ_PAUSED_TRIGGER_GRPS (  

SCHED_NAME VARCHAR(120) NOT NULL,  

TRIGGER_GROUP VARCHAR(200) NOT NULL,  

PRIMARY KEY (SCHED_NAME,TRIGGER_GROUP))  

ENGINE=InnoDB;  


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

ENGINE=InnoDB;  


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

ENGINE=InnoDB;  


CREATE TABLE QRTZ_LOCKS (  

SCHED_NAME VARCHAR(120) NOT NULL,  

LOCK_NAME VARCHAR(40) NOT NULL,  

PRIMARY KEY (SCHED_NAME,LOCK_NAME))  

ENGINE=InnoDB;  




-- 这是是索引了--------------------------------------------  

CREATE INDEX IDX_QRTZ_J_REQ_RECOVERY ON QRTZ_JOB_DETAILS(SCHED_NAME,REQUESTS_RECOVERY);  

CREATE INDEX IDX_QRTZ_J_GRP ON QRTZ_JOB_DETAILS(SCHED_NAME,JOB_GROUP);  


CREATE INDEX IDX_QRTZ_T_J ON QRTZ_TRIGGERS(SCHED_NAME,JOB_NAME,JOB_GROUP);  

CREATE INDEX IDX_QRTZ_T_JG ON QRTZ_TRIGGERS(SCHED_NAME,JOB_GROUP);  

CREATE INDEX IDX_QRTZ_T_C ON QRTZ_TRIGGERS(SCHED_NAME,CALENDAR_NAME);  

CREATE INDEX IDX_QRTZ_T_G ON QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_GROUP);  

CREATE INDEX IDX_QRTZ_T_STATE ON QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_STATE);  

CREATE INDEX IDX_QRTZ_T_N_STATE ON QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP,TRIGGER_STATE);  

CREATE INDEX IDX_QRTZ_T_N_G_STATE ON QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_GROUP,TRIGGER_STATE);  

CREATE INDEX IDX_QRTZ_T_NEXT_FIRE_TIME ON QRTZ_TRIGGERS(SCHED_NAME,NEXT_FIRE_TIME);  

CREATE INDEX IDX_QRTZ_T_NFT_ST ON QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_STATE,NEXT_FIRE_TIME);  

CREATE INDEX IDX_QRTZ_T_NFT_MISFIRE ON QRTZ_TRIGGERS(SCHED_NAME,MISFIRE_INSTR,NEXT_FIRE_TIME);  

CREATE INDEX IDX_QRTZ_T_NFT_ST_MISFIRE ON QRTZ_TRIGGERS(SCHED_NAME,MISFIRE_INSTR,NEXT_FIRE_TIME,TRIGGER_STATE);  

CREATE INDEX IDX_QRTZ_T_NFT_ST_MISFIRE_GRP ON QRTZ_TRIGGERS(SCHED_NAME,MISFIRE_INSTR,NEXT_FIRE_TIME,TRIGGER_GROUP,TRIGGER_STATE);  


CREATE INDEX IDX_QRTZ_FT_TRIG_INST_NAME ON QRTZ_FIRED_TRIGGERS(SCHED_NAME,INSTANCE_NAME);  

CREATE INDEX IDX_QRTZ_FT_INST_JOB_REQ_RCVRY ON QRTZ_FIRED_TRIGGERS(SCHED_NAME,INSTANCE_NAME,REQUESTS_RECOVERY);  

CREATE INDEX IDX_QRTZ_FT_J_G ON QRTZ_FIRED_TRIGGERS(SCHED_NAME,JOB_NAME,JOB_GROUP);  

CREATE INDEX IDX_QRTZ_FT_JG ON QRTZ_FIRED_TRIGGERS(SCHED_NAME,JOB_GROUP);  

CREATE INDEX IDX_QRTZ_FT_T_G ON QRTZ_FIRED_TRIGGERS(SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP);  

CREATE INDEX IDX_QRTZ_FT_TG ON QRTZ_FIRED_TRIGGERS(SCHED_NAME,TRIGGER_GROUP);  


commit;   


这里mysql的InnoDB,在mysql新版本中可有会存在字符过长的问题,VARCHAR(200),默认最长byte为767,200*4超过了767所有会有问题,这里可以打开mysql的innodb_large_prefix = true,默认是为false,或者把varchar改为190,可能会有问题,我这次暂时先改成190,尝试了了一个定时任务,暂时没发现有异常。


配置quartz.properties

#quartz是否自动启动,设为false将不会执行调度

org.quartz.autoStartup=false

#ID设置为自动获取 每一个必须不同 (所有调度器实例中是唯一的)

org.quartz.scheduler.instanceId=AUTO

org.quartz.scheduler.instanceName =DefaultQuartzScheduler

org.quartz.scheduler.rmi.export =false

org.quartz.scheduler.rmi.proxy =false

org.quartz.scheduler.wrapJobExecutionInUserTransaction =false

org.quartz.threadPool.class =org.quartz.simpl.SimpleThreadPool

org.quartz.threadPool.threadCount =10

org.quartz.threadPool.threadPriority =5

org.quartz.threadPool.threadsInheritContextClassLoaderOfInitializingThread =true

org.quartz.jobStore.misfireThreshold =60000

#org.quartz.jobStore.class = org.quartz.simpl.RAMJobStore

org.quartz.jobStore.class =org.quartz.impl.jdbcjobstore.JobStoreTX

#org.quartz.jobStore.driverDelegateClass=org.quartz.impl.jdbcjobstore.HSQLDBDelegate

org.quartz.jobStore.driverDelegateClass=org.quartz.impl.jdbcjobstore.StdJDBCDelegate

#org.quartz.jobStore.useProperties = true

org.quartz.jobStore.tablePrefix =QRTZ_

org.quartz.jobStore.isClustered =false

org.quartz.jobStore.maxMisfiresToHandleAtATime=1

配置:xml文件,或者直接写在项目xml文件里


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

<beans xmlns="http://www.springframework.org/schema/beans"

      xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context"

      xmlns:tx="http://www.springframework.org/schema/tx"

      xsi:schemaLocation="

http://www.springframework.org/schema/beans

http://www.springframework.org/schema/beans/spring-beans-3.2.xsd

http://www.springframework.org/schema/context

http://www.springframework.org/schema/context/spring-context-3.2.xsd

http://www.springframework.org/schema/tx

http://www.springframework.org/schema/tx/spring-tx-3.2.xsd">


    <bean name="scheduler" autowire="no" class="org.springframework.scheduling.quartz.SchedulerFactoryBean">


        <property name="startupDelay" value="3" /> // 延迟加载

<property name="autoStartup" value="true" /> //自动启动

<property name="applicationContextSchedulerContextKey" value="applicationContextKey" />

<property name="schedulerName" value="DefaultQuartzScheduler" />

<property name="configLocation" value="/WEB-INF/quartz.properties"/> // 选定配置文件

<property name="dataSource" ref="newsboard"/> //选定数据库

</bean>

</beans>


这里的双下划线注释均为写这篇的时间加上去了,程序代码需要删除

配置完成后

@Autowired

private Scheduler scheduler;

自动注入后,通过scheduler的a'pi对定时任务进行操作

添加corn调度任务:

private void addCronTriggerByExpression(HttpServletRequest request, HttpServletResponse response)throws Exception {

//获取触发器名称

    String triggerName = request.getParameter("triggerName");

String cronExpression = request.getParameter("cronExpression");

String jobClass=request.getParameter("jobClass");

if (StringUtils.isEmpty(triggerName) || StringUtils.isEmpty(cronExpression)) {

response.getWriter().println(1);

}

// 验证cronExpression表达式是否合法

    if(!CronExpression.isValidExpression(cronExpression)){

response.getWriter().println(1);

}

JobDetail jobDetail =null;

try{

Class obj=  Class.forName(jobClass);

String jobName = jobClass.substring(jobClass.lastIndexOf(".")+1);

jobDetail = JobBuilder.newJob(obj)

.withIdentity(jobName, Scheduler.DEFAULT_GROUP)

.build();

}catch(Exception e){

e.printStackTrace();

}

// 增加触发器

    schedulerService.schedule(triggerName, cronExpression, jobDetail);

// response.setContentType("text/xml;charset=utf-8");

    response.getWriter().println(0);

}


public void schedule(String name, CronExpression cronExpression,String group,JobDetail jobDetail) {

if (name ==null || name.trim().equals("")) {

name = UUID.randomUUID().toString();

}else{

//在名称后添加UUID,保证名称的唯一性

            name +="&"+UUID.randomUUID().toString();

}

try {

CronTrigger cronTrigger = TriggerBuilder.newTrigger()

.withIdentity(name, group)

.withSchedule(CronScheduleBuilder.cronSchedule(cronExpression))//在任务调度器中,使用任务调度器的 CronScheduleBuilder 来生成一个具体的 CronTrigger 对象

                    .build();

//注册作业和触发器

            scheduler.scheduleJob(jobDetail, cronTrigger);

//开始调度任务

//            scheduler.start();

        }catch (SchedulerException e) {

throw new RuntimeException(e);

}

}


添加一个简单定时任务:

/**

* 增加 Simple Trigger

*

* @param request

* @param response

*/

private void addSimpleTrigger(HttpServletRequest request, HttpServletResponse response)throws IOException {

// 获取前台所有配置参数

    Map tempMap = WebUtils.getParametersStartingWith(request,"p_");

Map filterMap =new HashMap();

for (String key : tempMap.keySet()){

filterMap.put (key, (String)tempMap.get(key));

}

String jobClass=request.getParameter("jobClass");

if (StringUtils.isEmpty(filterMap.get(QuartzConstants.STARTTIME))) {

response.getWriter().println(1);

}

JobDetail jobDetail=null;

try {

Class obj=  Class.forName(jobClass);

String jobName = jobClass.substring(jobClass.lastIndexOf(".")+1);

jobDetail = JobBuilder.newJob(obj)

.withIdentity(jobName,Scheduler.DEFAULT_GROUP)

.build();

}catch (Exception e) {

e.printStackTrace();

}

// 增加触发器

    schedulerService.schedule(filterMap,jobDetail);

// response.setContentType("text/xml;charset=utf-8");

    response.getWriter().println(0);

}


//停止触发,移除触发,删除触发

TriggerKey triggerKey = TriggerKey.triggerKey(triggerName,group);

// 停止触发器

            scheduler.pauseTrigger(triggerKey);

// 移除触发器

            return scheduler.unscheduleJob(triggerKey);

// 删除任务

//            return scheduler.deleteJob(JobKey.jobKey(jobname,group));

//重启触发器

scheduler.resumeTrigger(new TriggerKey(triggerName, group));

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 214,922评论 6 497
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,591评论 3 389
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 160,546评论 0 350
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,467评论 1 288
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,553评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,580评论 1 293
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,588评论 3 414
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,334评论 0 270
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,780评论 1 307
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,092评论 2 330
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,270评论 1 344
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,925评论 5 338
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,573评论 3 322
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,194评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,437评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,154评论 2 366
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,127评论 2 352

推荐阅读更多精彩内容