应该如何正确使用Quartz

应该如何正确使用Quartz,第1张

第一步

导入相关的jar包

第二步

创建定时任务

一个定时任务对应一个Job实现类。例如:

MyJob类为需要定时执行的类 --->

public class MyJob implements Job {

//MyJob类为需要定时执行的类,execute为定时执行的方法。一个定时任务对应一个Job实现类。

@Override

public void execute(JobExecutionContext arg0) throws JobExecutionException {

//业务逻辑

Systemoutprintln("执行时间:"+new Date());

}

}

第三步

执行都是任务

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

//SchedulerFactory 是一个接口,用于Scheduler的创建和管理

SchedulerFactory factory = new StdSchedulerFactory();

//从工厂里面拿到一个scheduler实例

//计划表(可能翻译的不太贴切),现在我们有了要做的内容,

//与调度程序交互的主要API

/

Scheduler的生命期,从SchedulerFactory创建它时开始,

到Scheduler调用shutdown()方法时结束;Scheduler被创建后,

可以增加、删除和列举Job和Trigger,以及执行其它与调度相关的 *** 作

(如暂停Trigger)。但是,Scheduler只有在调用start()方法后,

才会真正地触发trigger(即执行job)

/

Scheduler scheduler = factorygetScheduler();

//具体任务

//用于定义作业的实例

//JobBuilder - 用于定义/构建JobDetail实例,用于定义作业的实例。

JobDetail job = JobBuildernewJob(MyJobclass)withIdentity("job1", "group1")build();

//Trigger(即触发器) - 定义执行给定作业的计划的组件

//TriggerBuilder - 用于定义/构建触发器实例

CronTrigger trigger = TriggerBuildernewTrigger()withIdentity("trigger1", "group1")

withSchedule(CronScheduleBuildercronSchedule("0/1 "))build();

schedulerscheduleJob(job, trigger);

schedulerstart();

}

数据库中建表。建表模版在Quartz包下docs/dbTables下,选择相应的数据库和版本即可

ORACLE的11个Table列表如下: QRTZ_JOB_LISTENERS:存储有关已配置的 JobListener 的信息 JOB_NAME JOB_GROUP JOB_LISTENER QRTZ_TRIGGER_LISTENERS。

Job 包含了要执行任务的逻辑,但是 Job 对何时该执行却一无所知。这个事情留给了 Trigger。Quartz Trigger 继承了抽象的 orgquartzTrigger 类。当前,Quartz 有三个可用的 Trigger:

Java代码

·orgquartzSimpleTrigger

·orgquartzCronTrigger

·orgquartzNthIncludeDayTrigger

扩展资料:

Quartz框架的核心是调度器。调度器负责管理Quartz应用运行时环境。调度器不是靠自己做所有的工作,而是依赖框架内一些非常重要的部件。Quartz不仅仅是线程和线程管理。为确保可伸缩性,Quartz采用了基于多线程的架构。

启动时,框架初始化一套worker线程,这套线程被调度器用来执行预定的作业。这就是Quartz怎样能并发运行多个作业的原理。Quartz依赖一套松耦合的线程池管理部件来管理线程环境。

参考资料来源:百度百科-quartz

现象:在项目维护过程中,使用了Quartz框架,也就是定时执行任务的功能。但是,在多节点多并发的过程中,出现了一个问题,同一个trigger被多个机器重复的触发了。

Quartz的运行流程:

当任务达到触发条件的时候(当这条任务满足qrtz_cron_triggers表中定义的相关的时间表达式的时候)

qrtz_triggers表对应的这条记录的状态发生改变,同时下次触发时间根据时间表达式做出改变,同时根据sched_name找到qrtz_job_details

表中的具体job去执行

网上的解决办法:

整个过程就是:当job开始的时候去向zookeeper申请注册,只有当注册成功的时候才执行业务,失败则退出job。同时由于我这里是每天循环的

定时任务所以当zookeeper下的节点数目达到一定的个数的时候加一个删除锁(就是向zookeeper create一个ondetele节点),同时删除之前

的triggername节点,这样保证了明天这些任务可以继续完成。至此,任务重复执行的问题就解决了。

2网上有网友解释:如果我在10:00:00执行了一个任务,下次就是15s,但是如果服务器挂掉,我在10:00:50重新启动服务器,由于任务间隔是15s,所以从00-50s中间会有三个任务超时没有执行(本来应该分别是在15s,30s,45s执行),而超时的时间均小于1min,所以服务器启动以后会立即开启三个quartz线程来执行超时的任务。

方法1、通过改TOMCAT的配置文件serverxml配置

方法2、先把quartz配置信息提取出来,单独存成一个文件,比如applicationContext-quartzxml 然后修改webxml,让web容器启动时,可以加载该文件 。(此文没对此方法进行深入探究)

参考链接: >

spring 4x没有配置过,这里有一个spring 3x 的quartz定时配置,你参考参考:

<xml version="10" encoding="UTF-8">

<beans xmlns=">

quartz定时任务配置:

class="orgschelingquartz"

其中:

配置对应的定时任务,可配置多个,名称要唯一,对应的是第二步中配置的

配置,由于要实现动态读取定时任务周期时间,所以我们要写一个类实现,类的内容如下:

publicclassextendsimplements{

privatestaticfinallong=1L;

privatesysParamServiceImpl;

privateStringkey;

publicvoidsetKey(Stringkey)

{

thiskey=key;

}

publicvoidsetSysParamServiceImpl(SysParamServiceImplsysParamServiceImpl)

{

thissysParamServiceImpl=sysParamServiceImpl;

setCronExpression(getCronExpressionFromDB());

}

privateStringgetCronExpressionFromDB()

{

if(StringUtilsisEmpty(key))

return"000/1";

SysParamsysParam=newSysParam();

try

{

sysParam=sysParamServiceImplgetNameByKey(key);

}

catch(Exceptione)

{

eprintStackTrace();

}

if(sysParam!=null&&!StringUtilsisEmpty(sysParamgetParamValue()))

returnsysParamgetParamValue();

return"000/1";

}

}

简单说明一下:key是用来查询数据库配置的CronExpression表达式的查询条件,SysParamServiceImpl是实现查询的类,这几个参数都要从spring配置的CronTriggerFactoryBean参数获取,注意,配置的时候,key值的配置要在SysParamServiceImpl的配置之前,否则报空指针

spring配置CronTriggerFactoryBean:

实现了CronTriggerFactoryBean之后,开始配置CronTriggerFactoryBean,现在配置的是InitCronTriggerFactoryBean:

id对应quartz定时任务配置的,参数有三个,第二个和第三个是InitCronTriggerFactoryBean设置内容需要的,第一个则是定时任务执行业务逻辑的类

ps:,这个要配置对应的bean,我的是

配置对应的定时任务执行业务方法的类:

class="orgspringframeworkschelingquartzJobDetailFactoryBean"

简单说明一下:配置的是你需要定时执行的类,下面配置的是定时执行类中需要用到的其他类,这是由于项目启动执行定时任务不能在定时任务类中实例化这些类,要配置才行。

对应的定时任务执行类:

publicclassInquiryQuartzextendsQuartzJobBean{

@Autowired

privateInquiryServiceImplinquiryServiceImpl;

@Override

protectedvoidexecuteInternal(JobExecutionContextarg0)throwsJobExecutionException

{

//实例化接口

inquiryServiceImpl=(InquiryServiceImpl)arg0getJobDetail()getJobDataMap()get("inquiryServiceImpl");

//执行业务方法

quartzStart();

}

publicvoidquartzStart(){

//业务方法

}

}

说明一下:必须要实现QuartzJobBean接口

至此,就可以完成可配置CronExpression表达式的定时任务了!1

第一步:引包

要使用Quartz,必须要引入以下这几个包:

1、log4j-1216

2、quartz-217

3、slf4j-api-161jar

4、slf4j-log4j12-161jar

这些包都在下载的Quartz包里面包含着,因此没有必要为寻找这几个包而头疼。

第二步:创建要被定执行的任务类

这一步也很简单,只需要创建一个实现了orgquartzJob接口的类,并实现这个接口的唯一一个方法execute(JobExecutionContext arg0) throws JobExecutionException即可。如:

import javatextSimpleDateFormat;

import javautilDate;

import orgquartzJob;

import orgquartzJobExecutionContext;

import orgquartzJobExecutionException;

public class myJob implements Job {

@Override

public void execute(JobExecutionContext arg0) throws JobExecutionException {

SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss SSS");

Systemoutprintln(sdfformat(new Date()));

}

}

import javatextSimpleDateFormat;

import javautilDate;

import orgquartzJob;

import orgquartzJobExecutionContext;

import orgquartzJobExecutionException;

public class myJob implements Job {

@Override

public void execute(JobExecutionContext arg0) throws JobExecutionException {

SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss SSS");

Systemoutprintln(sdfformat(new Date()));

}

}

这个例子很简单,就不用解说了。

第三步:创建任务调度,并执行

这一步应该算是最难的一步的,但其实是非常简单的,直接上代码

import static orgquartzCronScheduleBuildercronSchedule;

import static orgquartzJobBuildernewJob;

import static orgquartzTriggerBuildernewTrigger;

import javatextSimpleDateFormat;

import javautilDate;

import orgquartzCronTrigger;

import orgquartzJobDetail;

import orgquartzScheduler;

import orgquartzSchedulerFactory;

import orgquartzimplStdSchedulerFactory;

public class Test {

public void go() throws Exception {

// 首先,必需要取得一个Scheduler的引用

SchedulerFactory sf = new StdSchedulerFactory();

Scheduler sched = sfgetScheduler();

//jobs可以在scheduled的schedstart()方法前被调用

//job 1将每隔20秒执行一次

JobDetail job = newJob(myJobclass)withIdentity("job1", "group1")build();

CronTrigger trigger = newTrigger()withIdentity("trigger1", "group1")withSchedule(cronSchedule("0/20 "))build();

Date ft = schedscheduleJob(job, trigger);

SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss SSS");

Systemoutprintln(jobgetKey() + " 已被安排执行于: " + sdfformat(ft) + ",并且以如下重复规则重复执行: " + triggergetCronExpression());

// job 2将每2分钟执行一次(在该分钟的第15秒)

job = newJob(myJobclass)withIdentity("job2", "group1")build();

trigger = newTrigger()withIdentity("trigger2", "group1")withSchedule(cronSchedule("15 0/2 "))build();

ft = schedscheduleJob(job, trigger);

Systemoutprintln(jobgetKey() + " 已被安排执行于: " + sdfformat(ft) + ",并且以如下重复规则重复执行: "+ triggergetCronExpression());

// 开始执行,start()方法被调用后,计时器就开始工作,计时调度中允许放入N个Job

schedstart();

try {

//主线程等待一分钟

Threadsleep(60L 1000L);

} catch (Exception e) {}

//关闭定时调度,定时器不再工作

schedshutdown(true);

}

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

Test test = new Test();

testgo();

}

}

import static orgquartzCronScheduleBuildercronSchedule;

import static orgquartzJobBuildernewJob;

import static orgquartzTriggerBuildernewTrigger;

import javatextSimpleDateFormat;

import javautilDate;

import orgquartzCronTrigger;

import orgquartzJobDetail;

import orgquartzScheduler;

import orgquartzSchedulerFactory;

import orgquartzimplStdSchedulerFactory;

public class Test {

public void go() throws Exception {

// 首先,必需要取得一个Scheduler的引用

SchedulerFactory sf = new StdSchedulerFactory();

Scheduler sched = sfgetScheduler();

//jobs可以在scheduled的schedstart()方法前被调用

//job 1将每隔20秒执行一次

JobDetail job = newJob(myJobclass)withIdentity("job1", "group1")build();

CronTrigger trigger = newTrigger()withIdentity("trigger1", "group1")withSchedule(cronSchedule("0/20 "))build();

Date ft = schedscheduleJob(job, trigger);

SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss SSS");

Systemoutprintln(jobgetKey() + " 已被安排执行于: " + sdfformat(ft) + ",并且以如下重复规则重复执行: " + triggergetCronExpression());

// job 2将每2分钟执行一次(在该分钟的第15秒)

job = newJob(myJobclass)withIdentity("job2", "group1")build();

trigger = newTrigger()withIdentity("trigger2", "group1")withSchedule(cronSchedule("15 0/2 "))build();

ft = schedscheduleJob(job, trigger);

Systemoutprintln(jobgetKey() + " 已被安排执行于: " + sdfformat(ft) + ",并且以如下重复规则重复执行: "+ triggergetCronExpression());

// 开始执行,start()方法被调用后,计时器就开始工作,计时调度中允许放入N个Job

schedstart();

try {

//主线程等待一分钟

Threadsleep(60L 1000L);

} catch (Exception e) {}

//关闭定时调度,定时器不再工作

schedshutdown(true);

}

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

Test test = new Test();

testgo();

}

}

OK了,Job1和Job2就会被安排为定时执行了。此时程序是可以执行的了,但是可能会输出WARN级别日志,这是因为没有加log4j的配置文件,加上配置文件,就OK了。这里需要说明的地方只有一个,其它的可以直接Copy到您的项目里面。看代码:

CronTrigger trigger = newTrigger()withIdentity("trigger1", "group1")withSchedule(cronSchedule("0/20 "))build();

CronTrigger trigger = newTrigger()withIdentity("trigger1", "group1")withSchedule(cronSchedule("0/20 "))build();

最近使用quartz做任务计划,有时需要将一些信息记录在jobDataMap中,情况如下,我的job已经注册到scheduler中并开始运行了,我在前台有些 *** 作,想在后台代码中去修改jobDataMap,但这段代码不是job的execute方法去完成的,而是我的Action直接获得这个job的jobDataMap去 *** 作,代码如下:

thisschedulergetJobDetail(jobName, jobGroup)getJobDataMap()put("planStatus", planStatus);

我想在我下次的 *** 作中获得到他,当然我指的是自己在Action中去手动的得到这个jobDataMap,然后再jobDataMapget("planStatus")取出,jobDataMap只是为我的Action *** 作充当了一个持久化保存的角色。但是我却发现后来去取planStatus时,始终无法取到,jobDataMap中没有这个数据。。请问如何解决呢

附,使用job,和StatefulJob好像都不行。。。StatefulJob只在job的execute方法中执行才能存储jobDataMap的值。。

以上就是关于应该如何正确使用Quartz全部的内容,包括:应该如何正确使用Quartz、Quartz怎么获取正在执行的Trigger的状态,即表QRTZ_FIRED_TRIGGERS中的状态呢、Quartz重复执行问题记录等相关内容解答,如果想了解更多相关内容,可以关注我们,你们的支持是我们更新的动力!

欢迎分享,转载请注明来源:内存溢出

原文地址:https://www.54852.com/web/9697302.html

(0)
打赏 微信扫一扫微信扫一扫 支付宝扫一扫支付宝扫一扫
上一篇 2023-05-01
下一篇2023-05-01

发表评论

登录后才能评论

评论列表(0条)

    保存