JavaShuo
Quartz深入浅出
时间 2021-01-12
什么是Quartz
Quartz是一个开源的作业调度框架,由java编写,在.NET平台为Quartz.Net,通过Quart可以快速完成任务调度的工作.
Quartz能干什么/应用场景
如网页游戏中挂机自动修炼如8个小时,人物相关数值进行成长,当使用某道具后,时间减少到4个小时,人物对应获得成长值.这其中就涉及到了Scheduler的操作,定时对人物进行更新属性操作,更改定时任务执行时间.
网页游戏中会大量涉及到Scheduler的操作,有兴趣的朋友可自行联想.
企业中如每天凌晨2点触发数据同步、发送Email等操作
同类框架对比
TimeTask TimeTask在Quartz前还是显得过于简单、不完善,不能直接满足开发者的较为复杂的应用场景.
资源
官网:http://www.quartz-scheduler.org/
下载:http://www.quartz-scheduler.org/downloads
maven pom
<dependency>
<groupId>org.quartz-scheduler</groupId>
<artifactId>quartz</artifactId>
<version>2.2.1</version>
</dependency>
<dependency>
<groupId>org.quartz-scheduler</groupId>
<artifactId>quartz-jobs</artifactId>
<version>2.2.1</version>
</dependency>
源代码 svn:http://svn.terracotta.org/svn/quartz
本文章采用的是2.21版本:
CSDN下载
:http://download.csdn.net/detail/chenweitang123/7636703
例子Demo:
CSDN下载
:整理完后上传.
框架分析
接口
类图
Quartz中的设计模式
Builder模式
所有关键组件都有Builder模式来构建 <Builder> 如:JobBuilder、TriggerBuilder
Factory模式
最终由Scheduler的来进行组合各种组件 <Factory> 如SchedulerFactory
Quartz项目中大量使用组件模式,插件式设计,可插拔,耦合性低,易扩展,开发者可自行定义自己的Job、Trigger等组件
链式写法,Quartz中大量使用链式写法,与jQuery的写法有几分相似,实现也比较简单,如:
$(this).addClass("divCurrColor").next(".divContent").css("display","block");
newTrigger
().withIdentity(
"trigger3"
,
"group1"
).startAt(
startTime
)
.withSchedule(
simpleSchedule
().withIntervalInSeconds(10).withRepeatCount(10)).build();
框架核心分析
SchedulerFactory -- 调度程序工厂
StdSchedulerFactory -- Quartz默认的SchedulerFactory
DirectSchedulerFactory --
DirectSchedulerFactory是对
SchedulerFactory的直接实现,通过它可以直接构建Scheduler、
threadpool
等
ThreadExecutor / DefaultThreadExecutor -- 内部线程操作对象
JobExecutionContext -- JOB上下文,保存着Trigger、
JobDeaitl
等信息,JOB的execute方法传递的参数就是对象的实例
JobExecutionContextImpl
Scheduler
-- 调度器
StdScheduler -- Quartz默认的Scheduler
RemoteScheduler -- 带有RMI功能的Scheduler
JOB
--任务对象
JobDetail -- 他是实现轮询的一个的回调类,可将参数封装成JobDataMap对象,Quartz将任务的作业状态保存在JobDetail中.
JobDataMap --
JobDataMap用来报错由JobDetail传递过来的任务实例对象
Trigger
SimpleTrigger <普通的Trigger> --
SimpleScheduleBuilder
CronTrigger <带Cron Like 表达式的Trigger> --
CronScheduleBuilder
CalendarIntervalTrigger <带日期触发的Trigger> --
CalendarIntervalScheduleBuilder
DailyTimeIntervalTrigger <按天触发的Trigger> --
DailyTimeIntervalScheduleBuilder
ThreadPool --
为Quartz运行任务时提供了一些线程
SimpleThreadPool --一个Quartz默认实现的简单线程池,它足够健壮,能够应对大部分常用场景
-----以上是Quartz涉及到的一些关键对象,详细的内容如有机会会在后续的文章中展开!
Quartz类图
类图中主要分为5块:Factory、Bulider、Scheduler、Trigger、JOB
思想
[java]
view plain
copy
// 1、工厂模式 构建Scheduler的Factory,其中STD为Quartz默认的Factory
// 开发者亦可自行实现自己的Factory;Job、Trigger等组件
SchedulerFactory sf =
new
StdSchedulerFactory();
// 2、通过SchedulerFactory构建Scheduler对象
Scheduler sched = sf.getScheduler();
// 3、org.quartz.DateBuilder.evenMinuteDate -- 通过DateBuilder构建Date
Date runTime = evenMinuteDate(
new
Date());
// 4、org.quartz.JobBuilder.newJob <下一分钟> --通过JobBuilder构建Job
JobDetail job = newJob(HelloJob.
class
).withIdentity(
"job1"
,
"group1"
).build();
// 5、通过TriggerBuilder进行构建Trigger
Trigger trigger = newTrigger().withIdentity(
"trigger1"
,
"group1"
)
.startAt(runTime).build();
// 6、工厂模式,组装各个组件<JOB,Trigger>
sched.scheduleJob (job, trigger);
// 7、start
sched.start();
try
{
Thread.sleep(65L * 1000L);
}
catch
(Exception e) {
}
// 8、通过Scheduler销毁内置的Trigger和Job
sched.shutdown(
true
);
一句话看懂Quartz
1、创建调度工厂(); //工厂模式
2、根据工厂取得调度器实例();
//工厂模式
3、
Builder模式构建子组件<Job,Trigger> // builder模式, 如JobBuilder、TriggerBuilder、DateBuilder
4、通过调度器组装子组件 调度器.组装<子组件1,
子组件2...
> //工厂模式
5、调度器.start();
//工厂模式
Hello Quartz / 本文通过一个简单的例子让大家快速了解Quartz,上手,并了解Quartz内的一些关键对象 如
Scheduler、Job、Trigger、JobExecutionContext
等对象
导入Quartz所需的两个jar包 <quartz-2.2.1.jarr、quartz-jobs-2.2.1.jar>
创建我们自己的Job类 HelloJob,进行简单的输出
[java]
view plain
copy
package
org.quartz.examples.examples01;
import
java.util.Date;
import
org.slf4j.Logger;
import
org.slf4j.LoggerFactory;
import
org.quartz.Job;
import
org.quartz.JobExecutionContext;
import
org.quartz.JobExecutionException;
/**
* hello world Quartz
* @author weeks
*
*/
public
class
HelloJob
implements
Job {
private
static
Logger _log = LoggerFactory.getLogger(HelloJob .
class
);
/**
* Job,Job需要一个公有的构造函数,否则Factory无法构建
*/
public
HelloJob() {
}
/**
* 实现execute方法
*/
public
void
execute(JobExecutionContext context)
throws
JobExecutionException {
_log.info(
"Hello World! - "
+
new
Date());
}
}
创建我们的Job运行例子
,在下一分钟执行我们自己Job
[java]
view plain
copy
package
org.quartz.examples.examples01;
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;
/**
* 此Demo将演示如何启动和关闭Quartz调度器,以及如何运作
* @author weeks
*
*/
public
class
SimpleExample {
public
void
run()
throws
Exception {
Logger log = LoggerFactory.getLogger(SimpleExample.
class
);
log.info(
"------- Initializing ----------------------"
);
// 1、工厂模式 构建Scheduler的Factory,其中STD为Quartz默认的Factory,开发者亦可自行实现自己的Factory;Job、Trigger等组件
SchedulerFactory sf =
new
StdSchedulerFactory();
// 2、通过SchedulerFactory获得Scheduler对象
Scheduler sched = sf.getScheduler();
log.info(
"------- Initialization Complete -----------"
);
// 3、org.quartz.DateBuilder.evenMinuteDate <下一分钟> -- 通过DateBuilder构建Date
Date runTime = evenMinuteDate(
new
Date());
log.info(
"------- Scheduling Job -------------------"
);
// 4、org.quartz.JobBuilder.newJob --通过JobBuilder构建Job
JobDetail job = newJob(HelloJob.
class
).withIdentity(
"job1"
,
"group1"
).build();
// 5、通过TriggerBuilder进行构建
Trigger trigger = newTrigger().withIdentity(
"trigger1"
,
"group1"
).startAt(runTime ).build();
// 6、工厂模式,组装各个组件<JOB,Trigger>
sched.scheduleJob(job, trigger);
// [group1.job1] will run at:
log.info(job.getKey() +
" will run at: "
+ runTime);
// 7、start
sched.start();
log.info(
"------- Started Scheduler -----------------"
);
log.info(
"------- Waiting 65 seconds... -------------"
);
try
{
// wait 65 seconds to show job
Thread.sleep(65L * 1000L);
// executing...
}
catch
(Exception e) {
//
}
// shut down the scheduler
log.info(
"------- Shutting Down ---------------------"
);
// 8、通过Scheduler销毁内置的Trigger和Job
sched.shutdown(
true
);
log.info(
"------- Shutdown Complete -----------------"
);
}
public
static
void
main(String[] args)
throws
Exception {
SimpleExample example =
new
SimpleExample();
example.run();
}
}
让我们来看看上面的代码究竟做了些什么:
创建一个Quartz Job类,必须实现
org.quartz.Job
,这个接口只有一个你要实现的方法,execute方法,其中execute的接口定义如下
void
execute(
JobExecutionContext
context
)
throws
JobExecutionException;
当Quartz调度器到约定的时间,它就会生成一个Job的实例,所以你实现Job接口 必须提供一个公有函数,否则会抛出异常,并调用execute方法.其中调度器只管执行,而不关心结果,除非抛出JobExecutionException异常.
JobExecutionContext
中封装有Quartz运行所需要的所有信息,可以参见下面具体的代码片段.
其中涉及到的
Scheduler、Job、Trigger
3个关键对象 (后续会专门介绍这3个对象)
其中
Scheduler
调度器对象,它的方法有start()、shutdown()等方法,负责管理整个调度作业.
Job
又与几个对象有关
Job、JobDetail、JobDataMap
通过类图来看他们之间的关系
通过类图可以很明显的看出由JobExecutionContext来组装各个子组件,我们看看JobExecutionContextImpl的源代码,它保存着所有上下文信息
[java]
view plain
copy
private
transient
Scheduler scheduler ;
private
Trigger trigger;
private
JobDetail jobDetail;
private
JobDataMap jobDataMap;
private
transient
Job job;
private
Calendar calendar;
private
boolean
recovering =
false
;
private
int
numRefires =
0
;
private
Date fireTime;
private
Date scheduledFireTime;
private
Date prevFireTime;
private
Date nextFireTime;
private
long
jobRunTime = -
1
;
private
Object result;
private
HashMap<Object, Object> data=
new
HashMap<Object, Object>();
关于
JobDetail
JobDetail不存储具体的实例,但它允许你定义一个实例,JobDetail 又指向JobDataMap
JobDetail持有Job的详细信息,如它所属的组,名称等信息
关于
JobDataMap
JobDataMap保存着任务实例的对象,并保持着他们状态信息,它是Map接口的实现,即你可以往里面put和get一些你想存储和获取的信息.
关于
Trigger
即根据具体约定的触发器,具体的如:SimpleTrigger、CronTrigger 等