Quartz简介
Quartz概述
Quartz是一款强大的开源任务调度框架。主要用到了Builder模式,factory模式,组件模式和链式写法。包括了三个核心概念,分别是调度器,任务和触发器。
重要组成部分
Job:实现任务逻辑的任务接口。
JobDetail:JobDetail为Job实例提供了许多设置属性,以及JobDataMap成员变量属性,它用来存储特定Job实例的状态信息,调度器需要借助JobDetail对象来添加Job实例。重要的属性如下:name、group、jobClass、jobDataMap。
JobDetail jobDetail = JobBuilder.newJob(HelloJob.class)
.withIdentity("myJob", "ground1").build();
System.out.println("jobDetail name:"+jobDetail.getKey().getName());// myJob
System.out.println("jobDetail group:"+jobDetail.getKey().getGroup());// ground1
System.out.println("jobDetail jobClass:"+jobDetail.getJobClass().getName());// com.study.quartz.HelloJob
JobBuilder,JobStore,Trigger,TriggerBuilder,ThreadPool,Scheduler
calendar:一个Trigger可以和多个Calendar关联,以排除或包含某些时间点。
监听器:JobListener,TriggerListener,ScheduerListener
Quartz的Hello Word
创建maven工程
创建一个maven工程,并引入Quartz的相关jar
<dependency>
<groupId>org.quartz-scheduler</groupId>
<artifactId>quartz</artifactId>
<version>2.3.0</version>
</dependency>
创建一个job类
import java.text.SimpleDateFormat;
import java.util.Date;
import org.quartz.Job;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
public class HelloJob implements Job{
@Override
public void execute(JobExecutionContext arg0) throws JobExecutionException {
//打印当前的执行时间
Date date = new Date();
SimpleDateFormat sf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
System.out.println("当前时间为:"+sf.format(date));
//编写具体的业务逻辑
System.out.println("Hello World");
}
}
创建一个Scheduler类
import java.text.SimpleDateFormat;
import java.util.Date;
import org.quartz.JobBuilder;
import org.quartz.JobDetail;
import org.quartz.Scheduler;
import org.quartz.SchedulerException;
import org.quartz.SchedulerFactory;
import org.quartz.SimpleScheduleBuilder;
import org.quartz.Trigger;
import org.quartz.TriggerBuilder;
import org.quartz.impl.StdSchedulerFactory;
public class HelloScheduler {
public static void main(String[] args) throws SchedulerException {
// 创建一个JobDetail实例,将实例与HelloJob绑定
JobDetail jobDetail = JobBuilder.newJob(HelloJob.class)
.withIdentity("myJob", "ground1").build();
// 创建一个Trigger实例,定义该Job立即执行,并且每隔两秒钟重复执行一次
Trigger trigger = TriggerBuilder
.newTrigger()
.withIdentity("myTrigger", "group1")
.startNow()
.withSchedule(
SimpleScheduleBuilder.simpleSchedule()
.withIntervalInSeconds(2).repeatForever())
.build();
//创建Schedule实例
SchedulerFactory sFactory = new StdSchedulerFactory();
Scheduler scheduler = sFactory.getScheduler();
scheduler.start();
//打印当前时间
Date date = new Date();
SimpleDateFormat sf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
System.out.println("当前时间为:"+sf.format(date));
scheduler.scheduleJob(jobDetail,trigger);
}
}
Job中的JobExecutionContext
- 当Scheduler调用一个job,就会将JobExecutionContext传递给Job的execute方法。
- Job可以通过JobExecutionContext对象访问到Quartz运行时候的环境以及Job本身的明细数据。
JobDataMap
- 在进行任务调度时JobDataMap存储在JobExecutionContext中,方便获取。
- JobDataMap可以用来装载任何可序列化的数据对象,当job实例对象被执行时这些参数对象就会传递给他。
- JobDataMap实现了JDK的Map接口,并且添加了一些方便的方法用来存取基本的数据类型。
JobDataMap的获取方式
我们修改了HelloScheduler类,并传入了一些我们自定义的参数和值,如何在job中获取这些值,就使用到了JobDataMap对象。
public class HelloScheduler {
public static void main(String[] args) throws SchedulerException {
// 创建一个JobDetail实例,将实例与HelloJob绑定
JobDetail jobDetail = JobBuilder.newJob(HelloJob.class)
.withIdentity("myJob", "ground1")
.usingJobData("message", "Hello job")
.usingJobData("doubleJobValue", 66.6).build();
// 创建一个Trigger实例,定义该Job立即执行,并且每隔两秒钟重复执行一次
Trigger trigger = TriggerBuilder
.newTrigger()
.withIdentity("myTrigger", "group1")
.usingJobData("message", "Hello trigger")
.usingJobData("doubleTrigglerValue", 88.8)
.startNow()
.withSchedule(
SimpleScheduleBuilder.simpleSchedule()
.withIntervalInSeconds(2).repeatForever())
.build();
//创建Schedule实例
SchedulerFactory sFactory = new StdSchedulerFactory();
Scheduler scheduler = sFactory.getScheduler();
scheduler.start();
//打印当前时间
Date date = new Date();
SimpleDateFormat sf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
System.out.println("当前时间为:"+sf.format(date));
scheduler.scheduleJob(jobDetail,trigger);
}
}
Job类中JobDataMap的获取方式如下,包含了如何获取trigger中的自定义的参数值。
public class HelloJob implements Job{
@Override
public void execute(JobExecutionContext context) throws JobExecutionException {
//打印当前的执行时间
Date date = new Date();
SimpleDateFormat sf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
System.out.println("当前时间为:"+sf.format(date));
//编写具体的业务逻辑
JobKey key = context.getJobDetail().getKey();
System.out.println("Job的name属性值和group属性值分别为:"+key.getName()+":"+key.getGroup());
TriggerKey trKey = context.getTrigger().getKey();
System.out.println("Trigger的name属性值和group属性值分别为:"+trKey.getName()+":"+trKey.getGroup());
JobDataMap dataMap = context.getJobDetail().getJobDataMap();
JobDataMap tDataMap = context.getTrigger().getJobDataMap();
String jobMsg = dataMap.getString("message");
double doubleJobValue = dataMap.getDouble("doubleJobValue");
String tiggerMsg = tDataMap.getString("message");
double doubleTrigglerValue = tDataMap.getDouble("doubleTrigglerValue");
System.out.println("jobMsg:"+jobMsg);
System.out.println("doubleJobValue:"+doubleJobValue);
System.out.println("tiggerMsg:"+tiggerMsg);
System.out.println("doubleTrigglerValue:"+doubleTrigglerValue);
}
}
输出结果为:
当前时间为:2018-01-22 17:03:29
Job的name属性值和group属性值分别为:myJob:ground1
Trigger的name属性值和group属性值分别为:myTrigger:group1
jobMsg:Hello job
doubleJobValue:66.6
tiggerMsg:Hello trigger
doubleTrigglerValue:88.8
也可以使用成员变量的getter和setter获取
修改job类的代码如下
public class HelloJob implements Job{
private String message;
private double doubleJobValue;
private double doubleTrigglerValue;
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
public double getDoubleJobValue() {
return doubleJobValue;
}
public void setDoubleJobValue(double doubleJobValue) {
this.doubleJobValue = doubleJobValue;
}
public double getDoubleTrigglerValue() {
return doubleTrigglerValue;
}
public void setDoubleTrigglerValue(double doubleTrigglerValue) {
this.doubleTrigglerValue = doubleTrigglerValue;
}
@Override
public void execute(JobExecutionContext context) throws JobExecutionException {
//打印当前的执行时间
Date date = new Date();
SimpleDateFormat sf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
System.out.println("当前时间为:"+sf.format(date));
//编写具体的业务逻辑
JobKey key = context.getJobDetail().getKey();
System.out.println("Job的name属性值和group属性值分别为:"+key.getName()+":"+key.getGroup());
TriggerKey trKey = context.getTrigger().getKey();
System.out.println("Trigger的name属性值和group属性值分别为:"+trKey.getName()+":"+trKey.getGroup());
System.out.println("Msg:"+message);
System.out.println("doubleJobValue:"+doubleJobValue);
System.out.println("doubleTrigglerValue:"+doubleTrigglerValue);
}
}
结果为
Job的name属性值和group属性值分别为:myJob:ground1
Trigger的name属性值和group属性值分别为:myTrigger:group1
Msg:Hello trigger
doubleJobValue:66.6
doubleTrigglerValue:88.8
认识Trigger
Quartz中的触发器是用来告诉调度程序作业什么时候触发,即Trigger对象是用来触发执行Job的。
触发器的通用属性
JobKey:表示job实例的标识,触发器被触发时,该指定的job实例会执行。
StartTime:表示触发器的时间表首次触发的时间,值为util.Date。
EndTime:指定触发器的不再被触发的时间,值为util.Date。
实例
HelloScheduler类中的startAt(date)和endAt(endDate)
public class HelloScheduler {
public static void main(String[] args) throws SchedulerException {
//打印当前时间
Date date = new Date();
SimpleDateFormat sf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
System.out.println("当前时间为:"+sf.format(date));
// 创建一个JobDetail实例,将实例与HelloJob绑定
JobDetail jobDetail = JobBuilder.newJob(HelloJob.class)
.withIdentity("myJob", "ground1")
.build();
//获取距离当前时间3秒后的时间
date.setTime(date.getTime()+3000);
//获取距离当前时间6秒后的时间
Date endDate = new Date();
endDate.setTime(endDate.getTime()+6000);
// 创建一个Trigger实例,定义该Job立即执行,并且每隔两秒钟重复执行一次
Trigger trigger = TriggerBuilder
.newTrigger()
.withIdentity("myTrigger", "group1")
.startAt(date)//开始执行时间为当前时间的后3秒
.endAt(endDate)//停止执行的时间为当前时间的后6秒
.withSchedule(
SimpleScheduleBuilder.simpleSchedule()
.withIntervalInSeconds(2).repeatForever())
.build();
//创建Schedule实例
SchedulerFactory sFactory = new StdSchedulerFactory();
Scheduler scheduler = sFactory.getScheduler();
scheduler.start();
scheduler.scheduleJob(jobDetail,trigger);
}
}
HelloJob中获取了开始执行时间和结束执行时间。
public class HelloJob implements Job{
@Override
public void execute(JobExecutionContext context) throws JobExecutionException {
//打印当前的执行时间
Date date = new Date();
SimpleDateFormat sf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
System.out.println("当前时间为:"+sf.format(date));
Trigger currentTrigger = context.getTrigger();
System.out.println("开始时间为:"+currentTrigger.getStartTime());
System.out.println("结束时间为:"+currentTrigger.getEndTime());
JobKey jobKey = currentTrigger.getJobKey();
System.out.println("jobKeyName:"+jobKey.getName()+"jobGroup:"+jobKey.getGroup());
}
}
认识SimpleTrigger
在一个指定时间段内执行一次作业任务,或是在指定的时间间隔内多次执行作业任务。
实例一
距离当前时间4秒后执行且执行一次
public class HelloJob implements Job{
@Override
public void execute(JobExecutionContext context) throws JobExecutionException {
//打印当前的执行时间
Date date = new Date();
SimpleDateFormat sf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
System.out.println("当前时间为:"+sf.format(date));
System.out.println("Hello world");
}
}
HelloScheduler类中代码如下
public class HelloScheduler {
public static void main(String[] args) throws SchedulerException {
//打印当前时间
Date date = new Date();
SimpleDateFormat sf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
System.out.println("当前时间为:"+sf.format(date));
// 创建一个JobDetail实例,将实例与HelloJob绑定
JobDetail jobDetail = JobBuilder.newJob(HelloJob.class)
.withIdentity("myJob", "ground1")
.build();
//距离当前时间4秒后执行且执行一次
date.setTime(date.getTime()+4000);
SimpleTrigger trigger = (SimpleTrigger)TriggerBuilder
.newTrigger()
.withIdentity("myTrigger", "group1")
.startAt(date)
.build();
//创建Schedule实例
SchedulerFactory sFactory = new StdSchedulerFactory();
Scheduler scheduler = sFactory.getScheduler();
scheduler.start();
scheduler.scheduleJob(jobDetail,trigger);
}
}
实例二
距距离当前时间4秒后首次执行任务之后每隔两秒重复执行一次,在第一次执行再连续执行三次
public class HelloScheduler {
public static void main(String[] args) throws SchedulerException {
//打印当前时间
Date date = new Date();
SimpleDateFormat sf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
System.out.println("当前时间为:" + sf.format(date));
// 创建一个JobDetail实例,将实例与HelloJob绑定
JobDetail jobDetail = JobBuilder.newJob(HelloJob.class)
.withIdentity("myJob", "ground1").build();
// 距距离当前时间4秒后首次执行任务之后每隔两秒重复执行一次,在第一次执行再连续执行三次
date.setTime(date.getTime() + 4000);
SimpleTrigger trigger = (SimpleTrigger) TriggerBuilder
.newTrigger()
.withIdentity("myTrigger", "group1")
.startAt(date)
.withSchedule(
SimpleScheduleBuilder
.simpleSchedule()
.withIntervalInSeconds(2)
.withRepeatCount(3))
.build();
// 创建Schedule实例
SchedulerFactory sFactory = new StdSchedulerFactory();
Scheduler scheduler = sFactory.getScheduler();
scheduler.start();
scheduler.scheduleJob(jobDetail, trigger);
}
}
实例三
距离当前时间4秒后首次执行,距离当前时间后6秒停止执行
public class HelloScheduler {
public static void main(String[] args) throws SchedulerException {
//打印当前时间
Date date = new Date();
SimpleDateFormat sf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
System.out.println("当前时间为:" + sf.format(date));
// 创建一个JobDetail实例,将实例与HelloJob绑定
JobDetail jobDetail = JobBuilder.newJob(HelloJob.class)
.withIdentity("myJob", "ground1").build();
// 距离当前时间4秒后首次执行,距离当前时间后6秒停止执行
date.setTime(date.getTime() + 4000);
Date endDate = new Date();
endDate.setTime(endDate.getTime()+6000);
SimpleTrigger trigger = (SimpleTrigger) TriggerBuilder
.newTrigger()
.withIdentity("myTrigger", "group1")
.startAt(date)
.endAt(endDate)
.withSchedule(
SimpleScheduleBuilder
.simpleSchedule()
.withIntervalInSeconds(2)
.withRepeatCount(3))
.build();
// 创建Schedule实例
SchedulerFactory sFactory = new StdSchedulerFactory();
Scheduler scheduler = sFactory.getScheduler();
scheduler.start();
scheduler.scheduleJob(jobDetail, trigger);
}
}
注意
重复次数withRepeatCount:可以是0,正整数或是SimpleTrigger.REPEAT_INDEFINITELY常量值
重复执行间隔withIntervalInSeconds:必须为0或者长整数
指定了endAt参数,就会覆盖重复执行的效果
认识CronTrigger
基于日历的作业调度器,而不是像SimpleTrigger那样精确的指定时间间隔,比SimpleTrigger更常用。
Cron表达式
用于配置CronTrigger实例,是由7个子表达式组成的字符串,描述了时间表的详细信息,格式为:
[秒][分] [小时][日] [月][周] [年]
实例一
使用CronTrigger 每秒钟触发一次任务
public class HelloScheduler {
public static void main(String[] args) throws SchedulerException {
//打印当前时间
Date date = new Date();
SimpleDateFormat sf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
System.out.println("当前时间为:" + sf.format(date));
// 创建一个JobDetail实例,将实例与HelloJob绑定
JobDetail jobDetail = JobBuilder.newJob(HelloJob.class)
.withIdentity("myJob").build();
// 每秒执行一次任务
CronTrigger trigger = (CronTrigger) TriggerBuilder
.newTrigger()
.withIdentity("myTrigger", "group1")
.withSchedule(
CronScheduleBuilder.cronSchedule("* * * * * ? *"))
.build();
// 创建Schedule实例
SchedulerFactory sFactory = new StdSchedulerFactory();
Scheduler scheduler = sFactory.getScheduler();
scheduler.start();
scheduler.scheduleJob(jobDetail, trigger);
}
}
注意,表达式中的空格和英文状态
Cron表达式特殊字符意义对应表
Cron表达式举例
实例:
2017年内的每天10点15分触发一次
0 15 10 ? * * 2017
每天的14点整至14点59分55秒,以及18点整至18点59分55秒,每5秒钟触发一次
0/5 * 14,18 * * ?
通配符说明
Cron表达式
- L和W可以一起使用,例如LW表示每个月的最后一个工作日
- 周字段英文字母不区分大小写
- 利用工具,在线生成百度搜索Crona表达式在线生成器
Scheduler-工厂模式
所有的Schedule实例应该有SchedulerFactory来创建,Quartz的三个核心概念是调度器,任务和触发器
关系如下:
Scheduler创建方式
SchedulerFactory sFactory = new StdSchedulerFactory();
Scheduler scheduler = sFactory.getScheduler();
DirectSchedulerFactory factory = DirectSchedulerFactory.getInstance();
Scheduler scheduler2 = factory.getScheduler();
StdSchedulerFactory
- 使用一组参数(Java.util.Properties)来创建和初始化Quartz调度器。
- 配置参数一般存储在quartz.properties中。
- 调用getScheduler方法就能创建和初始化调度器对象。
Scheduler的主要函数
- Date scheduleJob = scheduler.scheduleJob(jobDetail, trigger);绑定jobDetail和trigger,将它注册进Scheduler中,将trigger中的时间来触发jobDetail中的业务逻辑,返回的时间是最近一次的执行时间。
- void start();启动Scheduler
- void standdby();暂停
核心代码
SchedulerFactory sFactory = new StdSchedulerFactory();
Scheduler scheduler = sFactory.getScheduler();
scheduler.start();
scheduler.scheduleJob(jobDetail, trigger);
//scheduler执行两秒后挂起
Thread.sleep(2000L);
scheduler.standby();
//scheduler挂起三秒后重新执行
Thread.sleep(3000L);
scheduler.start();
执行结果为:
当前时间为:2018-01-24 15:25:20
Hello world
当前时间为:2018-01-24 15:25:21
Hello world
当前时间为:2018-01-24 15:25:22
Hello world
当前时间为:2018-01-24 15:25:25
Hello world
当前时间为:2018-01-24 15:25:25
Hello world
当前时间为:2018-01-24 15:25:25
Hello world
当前时间为:2018-01-24 15:25:26
Hello world
void shutdown();关闭
方法中可以传入一个布尔类型的参数,true表示等待所有正在执行的job执行完毕后,再关闭scheduler,false表示直接关闭scheduler。
quartz.properties
项目启动会加载项目根目录下的quartz.properties文件,没有就会加载jar下的quartz.properties文件,文件中的属性如下
- 调度器属性:org.quartz.scheduler.instanceName属性用来区分特定的调度器实例,可以按照功能用途来给调度器起名。
org.quartz.scheduler.instanceId属性和前者一样,也允许任何字符串,但是这个值必须在所有调度器实例中是唯一的,尤其在一个集群中,作为集群的唯一key。 - 线程池属性:重要的属性是threadCount,threadPriority优先值
- 作业存储设置:描述了调度器实例的生命周期,Job和Trigger信息是如何被存储的。
- 插件配置:满足特定需求用到的Quartz插件的配置。
quartz.properties文件实例
# Default Properties file for use by StdSchedulerFactory
# to create a Quartz Scheduler Instance, if a different
# properties file is not explicitly specified.
#
# ===========================================================================
# Configure Main Scheduler Properties 调度器属性
# ===========================================================================
org.quartz.scheduler.instanceName: DefaultQuartzScheduler
org.quartz.scheduler.instanceid:AUTO
org.quartz.scheduler.rmi.export: false
org.quartz.scheduler.rmi.proxy: false
org.quartz.scheduler.wrapJobExecutionInUserTransaction: false
# ===========================================================================
# Configure ThreadPool 线程池属性
# ===========================================================================
#线程池的实现类(一般使用SimpleThreadPool即可满足几乎所有用户的需求)
org.quartz.threadPool.class: org.quartz.simpl.SimpleThreadPool
#指定线程数,至少为1(无默认值)(一般设置为1-100直接的整数合适)
org.quartz.threadPool.threadCount: 10
#设置线程的优先级(最大为java.lang.Thread.MAX_PRIORITY 10,最小为Thread.MIN_PRIORITY 1,默认为5)
org.quartz.threadPool.threadPriority: 5
#设置SimpleThreadPool的一些属性
#设置是否为守护线程
#org.quartz.threadpool.makethreadsdaemons = false
#org.quartz.threadPool.threadsInheritContextClassLoaderOfInitializingThread: true
#org.quartz.threadpool.threadsinheritgroupofinitializingthread=false
#线程前缀默认值是:[Scheduler Name]_Worker
#org.quartz.threadpool.threadnameprefix=swhJobThead;
# 配置全局监听(TriggerListener,JobListener) 则应用程序可以接收和执行 预定的事件通知
# ===========================================================================
# Configuring a Global TriggerListener 配置全局的Trigger监听器
# MyTriggerListenerClass 类必须有一个无参数的构造函数,和 属性的set方法,目前2.2.x只支持原始数据类型的值(包括字符串)
# ===========================================================================
#org.quartz.triggerListener.NAME.class = com.swh.MyTriggerListenerClass
#org.quartz.triggerListener.NAME.propName = propValue
#org.quartz.triggerListener.NAME.prop2Name = prop2Value
# ===========================================================================
# Configuring a Global JobListener 配置全局的Job监听器
# MyJobListenerClass 类必须有一个无参数的构造函数,和 属性的set方法,目前2.2.x只支持原始数据类型的值(包括字符串)
# ===========================================================================
#org.quartz.jobListener.NAME.class = com.swh.MyJobListenerClass
#org.quartz.jobListener.NAME.propName = propValue
#org.quartz.jobListener.NAME.prop2Name = prop2Value
# ===========================================================================
# Configure JobStore 存储调度信息(工作,触发器和日历等)
# ===========================================================================
# 信息保存时间 默认值60秒
org.quartz.jobStore.misfireThreshold: 60000
#保存job和Trigger的状态信息到内存中的类
org.quartz.jobStore.class: org.quartz.simpl.RAMJobStore
# ===========================================================================
# Configure SchedulerPlugins 插件属性 配置
# ===========================================================================
# 自定义插件
#org.quartz.plugin.NAME.class = com.swh.MyPluginClass
#org.quartz.plugin.NAME.propName = propValue
#org.quartz.plugin.NAME.prop2Name = prop2Value
#配置trigger执行历史日志(可以看到类的文档和参数列表)
org.quartz.plugin.triggHistory.class = org.quartz.plugins.history.LoggingTriggerHistoryPlugin
org.quartz.plugin.triggHistory.triggerFiredMessage = Trigger {1}.{0} fired job {6}.{5} at: {4, date, HH:mm:ss MM/dd/yyyy}
org.quartz.plugin.triggHistory.triggerCompleteMessage = Trigger {1}.{0} completed firing job {6}.{5} at {4, date, HH:mm:ss MM/dd/yyyy} with resulting trigger instruction code: {9}
#配置job调度插件 quartz_jobs(jobs and triggers内容)的XML文档
#加载 Job 和 Trigger 信息的类 (1.8之前用:org.quartz.plugins.xml.JobInitializationPlugin)
org.quartz.plugin.jobInitializer.class = org.quartz.plugins.xml.XMLSchedulingDataProcessorPlugin
#指定存放调度器(Job 和 Trigger)信息的xml文件,默认是classpath下quartz_jobs.xml
org.quartz.plugin.jobInitializer.fileNames = my_quartz_job2.xml
#org.quartz.plugin.jobInitializer.overWriteExistingJobs = false
org.quartz.plugin.jobInitializer.failOnFileNotFound = true
#自动扫描任务单并发现改动的时间间隔,单位为秒
org.quartz.plugin.jobInitializer.scanInterval = 10
#覆盖任务调度器中同名的jobDetail,避免只修改了CronExpression所造成的不能重新生效情况
org.quartz.plugin.jobInitializer.wrapInUserTransaction = false
# ===========================================================================
# Sample configuration of ShutdownHookPlugin ShutdownHookPlugin插件的配置样例
# ===========================================================================
#org.quartz.plugin.shutdownhook.class = \org.quartz.plugins.management.ShutdownHookPlugin
#org.quartz.plugin.shutdownhook.cleanShutdown = true
#
# Configure RMI Settings 远程服务调用配置
#
#如果你想quartz-scheduler出口本身通过RMI作为服务器,然后设置“出口”标志true(默认值为false)。
#org.quartz.scheduler.rmi.export = false
#主机上rmi注册表(默认值localhost)
#org.quartz.scheduler.rmi.registryhost = localhost
#注册监听端口号(默认值1099)
#org.quartz.scheduler.rmi.registryport = 1099
#创建rmi注册,false/never:如果你已经有一个在运行或不想进行创建注册
# true/as_needed:第一次尝试使用现有的注册,然后再回来进行创建
# always:先进行创建一个注册,然后再使用回来使用注册
#org.quartz.scheduler.rmi.createregistry = never
#Quartz Scheduler服务端端口,默认是随机分配RMI注册表
#org.quartz.scheduler.rmi.serverport = 1098
#true:链接远程服务调度(客户端),这个也要指定registryhost和registryport,默认为false
# 如果export和proxy同时指定为true,则export的设置将被忽略
#org.quartz.scheduler.rmi.proxy = false
Quartz,SpringMVC,Spring
Quartz依赖的包如下:
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context-support</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-tx</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.quartz-scheduler</groupId>
<artifactId>quartz</artifactId>
<version>2.2.3</version>
</dependency>
使用Quartz配置作业的方式
第一种:MethodInvokingJobDetailFactoryBean,在dispatcher-servlet.xml中配置
<bean id="simpleJobDetail"
class="org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean">
<property name="targetObject" ref="myBean" />
<property name="targetMethod" value="printMessage" />
</bean>
SimpleTrigger的相关配置
<!-- 距离当前时间1秒之后执行,之后每隔两秒钟执行一次 -->
<bean id="mySimpleTrigger" class="org.springframework.scheduling.quartz.SimpleTriggerFactoryBean">
<property name="jobDetail" ref="simpleJobDetail"/>
<property name="startDelay" value="1000"/>
<property name="repeatInterval" value="2000"/>
</bean>
其中myBean的相关代码如下
@Component("myBean")
public class MyBean {
public void printMessage() {
// 打印当前的执行时间,格式为2017-01-01 00:00:00
Date date = new Date();
SimpleDateFormat sf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
System.out.println("MyBean Executes!" + sf.format(date));
}
}
第二种:JobDetailFactoryBean,在dispatcher-servlet.xml中配置
<bean id="firstComplexJobDetail"
class="org.springframework.scheduling.quartz.JobDetailFactoryBean">
<property name="jobClass"
value="com.imooc.springquartz.quartz.FirstScheduledJob" />
<property name="jobDataMap">
<map>
<entry key="anotherBean" value-ref="anotherBean" />
</map>
</property>
<property name="Durability" value="true"/>
</bean>
anotherBean的相关代码如下:
@Component("anotherBean")
public class AnotherBean {
public void printAnotherMessage() {
System.out.println("AnotherMessage");
}
}
FirstScheduledJob类相关代码如下
public class FirstScheduledJob extends QuartzJobBean{
private AnotherBean anotherBean;
public void setAnotherBean(AnotherBean anotherBean){
this.anotherBean = anotherBean;
}
@Override
protected void executeInternal(JobExecutionContext arg0)
throws JobExecutionException {
Date date = new Date();
SimpleDateFormat sf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
System.out.println("FirstScheduledJob Executes!" + sf.format(date));
this.anotherBean.printAnotherMessage();
}
}
myCronTrigger的相关配置如下
<!-- 每隔5秒钟执行一次 -->
<bean id="myCronTrigger" class="org.springframework.scheduling.quartz.CronTriggerFactoryBean">
<property name="jobDetail" ref="firstComplexJobDetail"/>
<property name="cronExpression" value="0/5 * * ? * *"/>
</bean>
两种方法的Scheduler的相关配置
<bean class="org.springframework.scheduling.quartz.SchedulerFactoryBean">
<property name="jobDetails">
<list>
<ref bean="simpleJobDetail"/>
<ref bean="firstComplexJobDetail"/>
</list>
</property>
<property name="triggers">
<list>
<ref bean="mySimpleTrigger"/>
<ref bean="myCronTrigger"/>
</list>
</property>
</bean>
完整项目
dispatcher-servlet.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:mvc="http://www.springframework.org/schema/mvc" xmlns:p="http://www.springframework.org/schema/p"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd"
default-lazy-init="true">
<!-- 通过mvc:resources设置静态资源,这样servlet就会处理这些静态资源,而不通过控制器 -->
<!-- 设置不过滤内容,比如:css,jquery,img 等资源文件 -->
<mvc:resources location="/*.html" mapping="/**.html" />
<mvc:resources location="/css/*" mapping="/css/**" />
<mvc:resources location="/js/*" mapping="/js/**" />
<mvc:resources location="/images/*" mapping="/images/**" />
<!-- 设定消息转换的编码为utf-8防止controller返回中文乱码 -->
<bean
class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter">
<property name="messageConverters">
<list>
<bean
class="org.springframework.http.converter.StringHttpMessageConverter">
<property name="supportedMediaTypes">
<list>
<value>text/html;charset=UTF-8</value>
</list>
</property>
</bean>
</list>
</property>
</bean>
<!-- 添加注解驱动 -->
<mvc:annotation-driven />
<!-- 默认扫描的包路径 -->
<context:component-scan base-package="com.imooc.springquartz" />
<!-- mvc:view-controller可以在不需要Controller处理request的情况,转向到设置的View -->
<!-- 像下面这样设置,如果请求为/,则不通过controller,而直接解析为/index.jsp -->
<mvc:view-controller path="/" view-name="index" />
<bean class="org.springframework.web.servlet.view.UrlBasedViewResolver">
<property name="viewClass"
value="org.springframework.web.servlet.view.JstlView"></property>
<!-- 配置jsp路径前缀 -->
<property name="prefix" value="/"></property>
<!-- 配置URl后缀 -->
<property name="suffix" value=".jsp"></property>
</bean>
<bean id="simpleJobDetail"
class="org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean">
<property name="targetObject" ref="myBean" />
<property name="targetMethod" value="printMessage" />
</bean>
<bean id="firstComplexJobDetail"
class="org.springframework.scheduling.quartz.JobDetailFactoryBean">
<property name="jobClass"
value="com.imooc.springquartz.quartz.FirstScheduledJob" />
<property name="jobDataMap">
<map>
<entry key="anotherBean" value-ref="anotherBean" />
</map>
</property>
<property name="Durability" value="true"/>
</bean>
<!-- 距离当前时间1秒之后执行,之后每隔两秒钟执行一次 -->
<bean id="mySimpleTrigger" class="org.springframework.scheduling.quartz.SimpleTriggerFactoryBean">
<property name="jobDetail" ref="simpleJobDetail"/>
<property name="startDelay" value="1000"/>
<property name="repeatInterval" value="2000"/>
</bean>
<!-- 每隔5秒钟执行一次 -->
<bean id="myCronTrigger" class="org.springframework.scheduling.quartz.CronTriggerFactoryBean">
<property name="jobDetail" ref="firstComplexJobDetail"/>
<property name="cronExpression" value="0/5 * * ? * *"/>
</bean>
<bean class="org.springframework.scheduling.quartz.SchedulerFactoryBean">
<property name="jobDetails">
<list>
<ref bean="simpleJobDetail"/>
<ref bean="firstComplexJobDetail"/>
</list>
</property>
<property name="triggers">
<list>
<ref bean="mySimpleTrigger"/>
<ref bean="myCronTrigger"/>
</list>
</property>
</bean>
</beans>