1、项目添加Maven依赖
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>hand</groupId>
<artifactId>quartz</artifactId>
<version>1.0-SNAPSHOT</version>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>1.6</source>
<target>1.6</target>
</configuration>
</plugin>
</plugins>
</build>
<dependencies>
<!--定时任务依赖-->
<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>
<!--日志依赖-->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>1.7.21</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<version>1.7.21</version>
</dependency>
</dependencies>
</project>
2、定义Job类实现Job接口中的execute方法
import org.quartz.*;
/**
* @author jiaqing.xu@hand-china.com
* @version 1.0
* @name
* @description
* @date 2018/8/21
*/
@DisallowConcurrentExecution
public class HelloJob implements Job {
@Override
public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException {
//获取jobDetail中的参数 该参数值的赋值在QuartzTest的jobDetail中申明
JobDataMap dataMap = jobExecutionContext.getJobDetail().getJobDataMap();
String leader = dataMap.getString("leader");
System.err.println("leader: "+leader);
}
}
3、定义监听器,监听器的作用是在Job执行的前、后去触发一些其他的动作
监听器需要去实现JobListener接口,实现其中的getName方法、jobToBeExecuted执行前的方法、jobExecutionVetoed方法、jobWasExecuted执行后的方法。
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
import org.quartz.JobListener;
/**
* @author jiaqing.xu@hand-china.com
* @version 1.0
* @name
* @description
* @date 2018/8/21
*/
public class MyJobListener implements JobListener {
@Override
public String getName() {
return "MyJobListener";
}
@Override
public void jobToBeExecuted(JobExecutionContext jobExecutionContext) {
System.out.println("This is my job listener start!");
}
@Override
public void jobExecutionVetoed(JobExecutionContext jobExecutionContext) {
System.out.println("MyJobListener.jobExecutionVetoed()");
}
@Override
public void jobWasExecuted(JobExecutionContext jobExecutionContext, JobExecutionException e) {
System.out.println("This is my job listener end!");
}
}
4、编写测试类,这个类是重点,涉及的就是如何定义调度器,如何定义JobDetail、如何定义触发器以及在调度器的作用下将JobDetail和触发器结合到一起来执行。
import org.quartz.*;
import org.quartz.impl.StdSchedulerFactory;
/**
* @author jiaqing.xu@hand-china.com
* @version 1.0
* @name
* @description
* @date 2018/8/21
*/
public class QuartzTest {
public static void main(String[] args) {
try {
// 从调度工厂类中获取调度类
Scheduler scheduler = StdSchedulerFactory.getDefaultScheduler();
// 添加job监听器
scheduler.getListenerManager().addJobListener(new MyJobListener());
// 创建工作
JobDetail job1 = JobBuilder
.newJob(HelloJob.class)
.withIdentity("myJob1", "group1")
.usingJobData("leader", "小明")
.build();
//简单类型触发器
Trigger trigger1 = TriggerBuilder
.newTrigger()
.withIdentity("myTrigger1", "group1")
.withSchedule(SimpleScheduleBuilder
.simpleSchedule()
.withIntervalInSeconds(5)
.repeatForever())
.build();
//cron类型触发器
/*Trigger trigger = TriggerBuilder
.newTrigger()
.withIdentity("myTrigger", "group1")
.withSchedule(
CronScheduleBuilder.cronSchedule("0/5 * * * * ?"))
.build();*/
// 开始调度
scheduler.start();
// 组装Job和触发器
scheduler.scheduleJob(job1, trigger1);
} catch (SchedulerException se) {
se.printStackTrace();
}
}
}
上面定义了一个Job其名字为myJob1,所属于的分组为group1,并赋予了初始值leader->“小明”到JobDataMap中,在HelloJob中可以从该map中取值存放在Map中的值。
定义触发器两种形式:SimpleTrigger以及CronTrigger
SimpleTrigger触发器:
SimpleTrigger可以满足的调度需求是:在具体的时间点执行一次,或者在具体的时间点执行,并且以指定的间隔重复执行若干次。比如,你有一个trigger,你可以设置它在2015年1月13日的上午11:23:54准时触发,或者在这个时间点触发,并且每隔2秒触发一次,一共重复5次。
根据描述,你可能已经发现了,SimpleTrigger的属性包括:开始时间、结束时间、重复次数以及重复的间隔。这些属性的含义与你所期望的是一致的,只是关于结束时间有一些地方需要注意。
重复次数,可以是0、正整数,以及常量SimpleTrigger.REPEAT_INDEFINITELY。重复的间隔,必须是0,或者long型的正数,表示毫秒。注意,如果重复间隔为0,trigger将会以重复次数并发执行(或者以scheduler可以处理的近似并发数)。
可能的实现形式如下:
- 指定时间触发,不重复
SimpleTrigger trigger = (SimpleTrigger) newTrigger()
.withIdentity("trigger1", "group1")
.startAt(myStartTime) // some Date
.forJob("job1", "group1") // identify job with name, group strings
.build();
- 指定时间触发,每隔10秒执行一次,重复10次
trigger = newTrigger()
.withIdentity("trigger3", "group1")
.startAt(myTimeToStartFiring) // if a start time is not given (if this line were omitted), "now" is implied
.withSchedule(simpleSchedule()
.withIntervalInSeconds(10)
.withRepeatCount(10)) // note that 10 repeats will give a total of 11 firings
.forJob(myJob) // identify job with handle to its JobDetail itself
.build();
- 5分钟以后开始触发,仅执行一次
trigger = (SimpleTrigger) newTrigger()
.withIdentity("trigger5", "group1")
.startAt(futureDate(5, IntervalUnit.MINUTE)) // use DateBuilder to create a date in the future
.forJob(myJobKey) // identify job with its JobKey
.build();
CronTrigger触发器:
CronTrigger通常比Simple Trigger更有用,如果您需要基于日历的概念而不是按照SimpleTrigger的精确指定间隔进行重新启动的作业启动计划。
使用CronTrigger,您可以指定号时间表,例如“每周五中午”或“每个工作日和上午9:30”,甚至“每周一至周五上午9:00至10点之间每5分钟”和1月份的星期五“。
即使如此,和SimpleTrigger一样,CronTrigger有一个startTime,它指定何时生效,以及一个(可选的)endTime,用于指定何时停止计划。
Cron-Expressions用于配置CronTrigger的实例。Cron Expressions是由七个子表达式组成的字符串,用于描述日程表的各个细节。这些子表达式用空格分隔,并表示:
- Seconds
- Minutes
- Hours
- Day-of-Month
- Month
- Day-of-Week
- Year (optional field)
一个完整的Cron-Expressions的例子是字符串“0 0 12?* WED“ - 这意味着”每个星期三下午12:00“。
单个子表达式可以包含范围和/或列表。例如,可以用“MON-FRI”,“MON,WED,FRI”或甚至“MON-WED,SAT”代替前一个(例如“WED”)示例中的星期几字段。
通配符(' '字符)可用于说明该字段的“每个”可能的值。因此,前一个例子的“月”字段中的“”字符仅仅是“每个月”。因此,“星期几”字段中的“*”显然意味着“每周的每一天”。
所有字段都有一组可以指定的有效值。这些值应该是相当明显的 - 例如秒和分钟的数字0到59,数小时的值0到23。日期可以是1-31的任何值,但是您需要注意在给定的月份中有多少天!月份可以指定为0到11之间的值,或者使用字符串JAN,FEB,MAR,APR,MAY,JUN,JUL,AUG,SEP,OCT,NOV和DEC。星期几可以指定为1到7(1 =星期日)之间的值,或者使用字符串SUN,MON,TUE,WED,THU,FRI和SAT。
'/'字符可用于指定值的增量。例如,如果在“分钟”字段中输入“0/15”,则表示“每隔15分钟,从零开始”。如果您在“分钟”字段中使用“3/20”,则意味着“每隔20分钟,从三分钟开始” - 换句话说,它与“分钟”中的“3,243,43”相同领域。请注意“ / 35”的细微之处并不代表“每35分钟” - 这意味着“每隔35分钟,从零开始” - 或者换句话说,与指定“0,35”相同。
'?' 字符是允许的日期和星期几字段。用于指定“无特定值”。当您需要在两个字段中的一个字段中指定某个字符而不是另一个字段时,这很有用。请参阅下面的示例(和CronTrigger JavaDoc)以进行说明。
“L”字符允许用于月日和星期几字段。这个角色对于“最后”来说是短暂的,但是在这两个领域的每一个领域都有不同的含义。例如,“月”字段中的“L”表示“月的最后一天” - 1月31日,非闰年2月28日。如果在本周的某一天使用,它只是意味着“7”或“SAT”。但是如果在星期几的领域中再次使用这个值,就意味着“最后一个月的xxx日”,例如“6L”或“FRIL”都意味着“月的最后一个星期五”。您还可以指定从该月最后一天的偏移量,例如“L-3”,这意味着日历月份的第三个到最后一天。当使用'L'选项时,重要的是不要指定列表或值的范围,因为您会得到混乱/意外的结果。
“W”用于指定最近给定日期的工作日(星期一至星期五)。例如,如果要将“15W”指定为月日期字段的值,则意思是:“最近的平日到当月15日”。
'#'用于指定本月的“第n个”XXX工作日。例如,“星期几”字段中的“6#3”或“FRI#3”的值表示“本月的第三个星期五”。
记忆这些太过于复杂了,实际开发中可以借助一个在线的cron生成网站:http://cron.qqe2.com/
上面的定时任务执行的结果如下:
5、配置quartz.properties文件来修改定时任务的默认行为
所有的配置信息需要根据项目的实际动态来调整和配置。
参考资料:https://www.w3cschool.cn/quartz_doc/quartz_doc-2put2clm.html