一、什么是quartz作业调度?
Quartz是一个完全由java编写的开源作业调度框架。不要让作业调度这个术语吓着你。尽管Quartz框架整合了许多额外功能,比另一个调度框架Timer强大了许多,但是它使用也不难,下面我废话不多说,直奔主题。
二、quartz的体系结构。
1.quartz中使用了一下几种设计模式。
2.三个主要的概念
触发器:简单的讲就是调度作业,什么时候开始执行,什么时候结束执行。
3.quartz的体系结构
quartz框架至少有三百多个类组成,这里我们重点介绍几个它的核心部分
JobDetail:quartz每次都会直接创建一个JobDetail,同时创建一个Job实例,它不直接接受一个Job的实例,但是它接受一个Job的实现类,通过new instance()的反射方式来实例一个Job,在这里Job是一个接口,我们需要自己编写类去实现这个接口。下面我们会讲到这个接口。
Scheduler:调度器,JobDetail和Trigger可以通过Scheduler绑定到一起。
4.quartz重要组成部分
1).Job接口:可以通过实现该就接口来实现我们自己的业务逻辑,该接口只有execute()一个方法,我们可以通过下面的方式来实现Job接口来实现我们自己的业务逻辑
public class HelloJob implements Job{
public void execute(JobExecutionContext context) throws JobExecutionException {
//编写我们自己的业务逻辑
}
2).JobDetail:
每次都会直接创建一个JobDetail,同时创建一个Job实例,它不直接接受一个Job的实例,但是它接受一个Job的实现类,通过new instance()的反射方式来实例一个Job.可以通过下面的方式将一个Job实现类绑定到JobDetail中
JobDetail jobDetail=JobBuilder.newJob(HelloJob.class).
withIdentity("myJob", "group1")
.build();
3)JobBuiler:
主要是用来创建jobDeatil实例
4)JobStore:
绑定了Job的各种数据
5)trigger:前文讲到它主要用来执行Job实现类的业务逻辑的,我们可以通过下面的代码来创建一个Trigger实例:(这里我们会看到cron表达式,可以先不用,我们后面会介绍)
CronTrigger trigger = (CronTrigger) TriggerBuilder
.newTrigger()
.withIdentity("myTrigger", "group1") //创建一个标识符
.startAt(date)//什么时候开始触发
//每秒钟触发一次任务
.withSchedule(CronScheduleBuilder.cronSchedule("* * * * * ? *"))
.build();
6)Scheduler:创建Scheduler有两种方式
通过StdSchedulerFactory来创建
SchedulerFactory sfact=new StdSchedulerFactory();
Scheduler scheduler=sfact.getScheduler();
通过DirectSchedulerFactory来创建
DiredtSchedulerFactory factory=DirectSchedulerFactory.getInstance();
Scheduler scheduler=factory.getScheduler();
Scheduler 配置参数一般存储在quartz.properties中,我们可以修改参数来配置相应的参数。通过调用getScheduler()方法就能创建和初始化调度对象。
Scheduler的主要函数介绍:
Date schedulerJob(JobDetail,Trigger trigger);返回最近触发的一次时间
void standby()暂时挂起
void shutdown()完全关闭,不能重新启动了
shutdown(true)表示等待所有正在执行的job执行完毕之后,再关闭scheduler
shutdown(false)即直接关闭scheduler
在这里我们不得不提一下quartz.properties这个资源文件,在org.quartz这个包下,当我们程序启动的时候,它首先会到我们的根目录下查看是否配置了该资源文件,如果没有就会到该包下读取相应信息,当我们咋实现更复杂的逻辑时,需要自己指定参数的时候,可以自己配置参数来实现。下面我们简单看一下这个资源文件:
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.scheduler.instanceName属性用来区分特定的调度器实例,可以按照功能用途来给调度器起名。
org.quartz.scheduler.instanceId属性和前者一样,也允许任何字符串,但这个值必须是在所有调度器实例中是唯一的,尤其是在一个集群当中,作为集群的唯一key,假如你想quartz帮你生成这个值的话,可以设置我Auto
线程池属性:
threadCount设置线程的数量
threadPriority设置线程的优先级
org.quartz.threadPool.class 线程池的实现
作业存储设置:
描述了在调度器实例的声明周期中,job和trigger信息是怎么样存储的
插件配置:
满足特定需求用到的quartz插件的配置
5.监听器
监听器顾名思义,就是对事件进行监听并且加入自己相应的业务逻辑,主要有以下三个监听器分别对Job,Trigger,Scheduler进行监听。
三、Cron表达式
在这里,我们着重讲解一下cron表达式,quartz之所以能够实现更加复杂的业务逻辑,主要在依赖于cron表达式。
cron表达式编写的顺序一次是”秒 分 时 日 月 周 年”。
在这里我们可以看两张图片就能了解到cron表达式的基本语法了。
通过上面几张照片的介绍及实例讲解相信都对cron表达式有所了解吧,讲了这么多理论知识下面我们进入实战部分。
四、quartz框架实战
这里我们简要讲解一个我们这个实例,我们先实现Job接口来编写我们相应的业务逻辑,然后创建JobDetail实例将job实现类绑定,接着创建Trigger,然后创建Scheduler实例将JobDetail实例和Trigger绑定到一起。
不好意思,在这里我们漏掉了一个重要的属性(不好意思 ,hhhhhhhhh)
JobDataMap主要用啦设置和获取一些自定义的参数,比如JobDetail和trigger的name和group属性。它可以通过两种方式来获取和设置参数。
1.第一种方式,通过map的方式获取JobDataMap中的值,JobDataMap获取自定义的一些参数,下面这段代码获取的是我们即将要写的例子中的JobDetail和trigger的一些自定义参数(在实例中我们将省略这些代码,避免复杂性)
JobDataMap jobDataMap=context.getJobDetail().getJobDataMap();
JobDataMap tDataMap=context.getTrigger().getJobDataMap();
// JobDataMap jobDataMap2=context.getMergedJobDataMap(); //把两个map合并
String jobMsg=jobDataMap.getString("msg");
float jobFloat=jobDataMap.getFloat("JobFloatValue");
String triMsg=tDataMap.getString("msg");
double triDouble=tDataMap.getDouble("TriggerDoubleValue");
System.out.println("job message are:"+jobMsg+" "+jobFloat);
System.out.println("trigger message are:"+triMsg+" "+triDouble);
2.第二种方式,创建每一个key的属性,并且创建set,get方法,然后在Job实现类中通过set和get方法来获取信息。
private String msg;
private float JobFloatValue;
private double TriggerDoubleValue;
public void setJobFloatValue(float jobFloatValue) {
JobFloatValue = jobFloatValue;
}
public float getJobFloatValue() {
return JobFloatValue;
}
public void setMsg(String msg) {
this.msg = msg;
}
public String getMsg() {
return msg;
}
public void setTriggerDoubleValue(double triggerDoubleValue) {
TriggerDoubleValue = triggerDoubleValue;
}
public double getTriggerDoubleValue() {
return TriggerDoubleValue;
}
好了,终于讲完了,下面我们继续我们的实例。
下面是Job实现类
public class HelloJob implements Job{
//JobExecutionContext 提供了调度上下文的各种参数
public void execute(JobExecutionContext context) throws JobExecutionException {
//编写具体的逻辑关系
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
//打印当前时间
SimpleDateFormat simpleDateFormat =new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
System.out.println("Current time is :"+simpleDateFormat.format(new Date()));
System.out.println("Hello World");
}
触发器:
public class HelloSchedule{
public static void main(String[] args) throws SchedulerException, InterruptedException {
//创建一个JobDetail实例,与HelloJob class绑定
JobDetail jobDetail=JobBuilder.newJob(HelloJob.class).
withIdentity("myJob", "group1")
.build();
Date date=new Date();
//使用CronTrigger每秒钟触发一次任务
CronTrigger trigger = (CronTrigger) TriggerBuilder
.newTrigger()
.withIdentity("myTrigger", "group1") //创建一个标识符
.startAt(date)
//每秒钟触发一次任务
.withSchedule(CronScheduleBuilder.cronSchedule("* * * * * ? *"))
.build();
//创建一个schedule实例
SchedulerFactory schedulerFactory=new StdSchedulerFactory();
Scheduler scheduler=schedulerFactory.getScheduler();
scheduler.start();
//打印当前时间
SimpleDateFormat simpleDateFormat =new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
System.out.println("Current time is :"+simpleDateFormat.format(new Date()));
System.out.println("Current time is :"+scheduler.scheduleJob(jobDetail, trigger))
}
}
至此,我们完成了我们的第一个实例,每个一秒中执行我们的业务,即每个一秒中打印一次信息。
五,整合spring框架
quartz的强大还在于它可以和各种框架进行无缝整合,当然包括最流行的spring框架。下面我们来整合spring。
首先建立maven项目导入相关依赖,在这里我们不讲如何搭建spring框架,读者需要有spring的知识。
pom.xml文件
<dependencies>
<dependency>
<groupId>junitgroupId>
<artifactId>junitartifactId>
<version>3.8.1version>
<scope>testscope>
dependency>
<dependency>
<groupId>org.springframeworkgroupId>
<artifactId>spring-webmvcartifactId>
<version>4.3.12.RELEASEversion>
dependency>
<dependency>
<groupId>org.springframeworkgroupId>
<artifactId>spring-contextartifactId>
<version>4.3.12.RELEASEversion>
dependency>
<dependency>
<groupId>org.springframeworkgroupId>
<artifactId>spring-coreartifactId>
<version>4.3.12.RELEASEversion>
dependency>
<dependency>
<groupId>org.springframeworkgroupId>
<artifactId>spring-beansartifactId>
<version>4.3.12.RELEASEversion>
dependency>
<dependency>
<groupId>org.springframeworkgroupId>
<artifactId>spring-webartifactId>
<version>4.3.12.RELEASEversion>
dependency>
<dependency>
<groupId>org.springframeworkgroupId>
<artifactId>spring-aopartifactId>
<version>4.3.12.RELEASEversion>
dependency>
<dependency>
<groupId>io.rest-assuredgroupId>
<artifactId>spring-mock-mvcartifactId>
<version>3.0.1version>
dependency>
<dependency>
<groupId>org.springframeworkgroupId>
<artifactId>spring-context-supportartifactId>
<version>4.3.12.RELEASEversion>
dependency>
<dependency>
<groupId>org.springframeworkgroupId>
<artifactId>spring-txartifactId>
<version>4.3.12.RELEASEversion>
dependency>
<dependency>
<groupId>org.quartz-schedulergroupId>
<artifactId>quartzartifactId>
<version>2.3.0version>
dependency>
dependencies>
然后,我们在src/main/java目录下创建几个bean类,分别对应着我们的JobDetail,Trigger,和Scheduler,这里显而易见,我们通过spring容器来实例化bean,然后在spring中的配置文件中来用Scheduler把JobDetail和Trigger来绑定到一起,来实现业务逻辑。
Mybean.java:
@Component("myBean")
public class MyBean {
public void printMessage(){
Date date=new Date();
SimpleDateFormat sdf=new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
System.out.println("It is mybean "+sdf.format(date));
}
}
FristSchedulerJob.java
@Component("fristSchedulerJob")
public class FristSchedulerJob extends QuartzJobBean{
private AnotherBean anotherBean;
public void setAnotherBean(AnotherBean anotherBean) {
this.anotherBean = anotherBean;
}
@Override
protected void executeInternal(JobExecutionContext context)
throws JobExecutionException {
Date date=new Date();
SimpleDateFormat sdf=new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
System.out.println("It is my frist job "+sdf.format(date));
this.anotherBean.printAotherMessage();
}
}
AnotherBean.java
@Component("anotherBean")
public class AnotherBean {
public void printAotherMessage(){
System.out.println("AnotherBean");
}
}
下面我们看spring的配置文件,在这里需要说明的是我们通过controller对web请求进行管理控制,quartz在后台进行调度业务。
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:p="http://www.springframework.org/schema/p"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd">
<bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="viewClass" value="org.springframework.web.servlet.view.JstlView"/>
<property name="prefix" value="/WEB-INF/jsp/"/>
<property name="suffix" value=".jsp"/>
bean>
<bean id="simpleJobDetail" class="org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean">
<property name="targetObject" ref="myBean"/>
<property name="targetMethod" value="printMessage"/>
bean>
<bean id="fristComplexJobDetail" class="org.springframework.scheduling.quartz.JobDetailFactoryBean">
<property name="jobClass" value="cn.shinelon.quartz.FristSchedulerJob"/>
<property name="jobDataMap">
<map>
<entry key="anotherBean" value-ref="anotherBean"/>
map>
property>
<property name="durability" value="true"/>
bean>
<bean id="simpleTrigger" class="org.springframework.scheduling.quartz.SimpleTriggerFactoryBean">
<property name="jobDetail" ref="simpleJobDetail"/>
<property name="startDelay" value="1000"/>
<property name="repeatInterval" value="2000"/>
bean>
<bean id="myCronTrigger" class="org.springframework.scheduling.quartz.CronTriggerFactoryBean">
<property name="jobDetail" ref="fristComplexJobDetail"/>
<property name="cronExpression" value="0/5 * * ? * *"/>
bean>
<bean class="org.springframework.scheduling.quartz.SchedulerFactoryBean">
<property name="jobDetails">
<list>
<ref bean="simpleJobDetail"/>
<ref bean="fristComplexJobDetail"/>
list>
property>
<property name="triggers">
<list>
<ref bean="simpleTrigger"/>
<ref bean="myCronTrigger"/>
list>
property>
bean>
<context:component-scan base-package="cn.shinelon">context:component-scan>
beans>
在这里我们省略controller层和web.xml文件的代码,相信大家都能够自己完成。
至此,我们完成了对spring的整合,怎么样,有没有感受到quartz框架的强大(反正我没有感受到,哈哈哈哈哈,累死了,敲了一下午代码,赶紧去吃饭,溜了溜了)。