您的位置:首页 > 其它

Quartz学习---入门demo【任务调度的运行信息在内存】(一)

2018-03-09 14:57 736 查看
定时任务经常使用,从未研究其内部原理等。实际项目中多机部署时遇到问题,项目部署在不同服务器上。同一时间同时启动怕出现错误。于是有了此篇文章。

首先先从简单的demo入手(log4j.properties未配置,任务调度的运行信息在内存):

使用SimpleTrigger

1. 新建了一个Java类让它实现quartz的job方法,这就是一个简单的job。

/**
* 简单的job类
*
*/
public class SimpleJob implements Job{

@Override
public void execute(JobExecutionContext jobContext) throws JobExecutionException {
System.out.println("jobContext.getTrigger():"+jobContext.getTrigger().getJobDataMap()+"时间"+new Date());
}

}


2.Quartz在每次执行Job时,都重新创建一个Job实例,所以它不直接接受一个Job的实例,相反它接收一个Job实现类,以便运行时通过newInstance()的反射机制实例化Job。因此需要通过一个类来描述Job的实现类及其它相关的静态信息,如Job名字、描述、关联监听器等信息,JobDetail承担了这一角色。因此我们还需要创建一个JobDetail实例并且指定是那个job.最后定义我们的触发规则类,只有触发规则和我们的job关联起来才能实现我们想要的功能。

public class SimpleTrigger {

public static void main(String[] args) throws SchedulerException {
// 定义一个jobDetail
JobDetail jobDetail = JobBuilder.newJob(SimpleJob.class).build();
// 定义一个触发规则每5秒触发一次总计3次
Trigger trigger = TriggerBuilder.newTrigger()
.withSchedule(SimpleScheduleBuilder.simpleSchedule()
.withIntervalInSeconds(5).withRepeatCount(3))
.build();
//通过SchedulerFactory获取一个调度器实例
SchedulerFactory schedulerFactory = new StdSchedulerFactory();
Scheduler scheduler = schedulerFactory.getScheduler();
scheduler.scheduleJob(jobDetail, trigger);
//启动调度
scheduler.start();

}

}


执行结果: 刚启动有一次定义了三次共4次

log4j:WARN Please initialize the log4j system properly.
log4j:WARN See http://logging.apache.org/log4j/1.2/faq.html#noconfig for more info.
2018-03-09 10:56:38Hello Quartz!
2018-03-09 10:56:43Hello Quartz!
2018-03-09 10:56:48Hello Quartz!
2018-03-09 10:56:53Hello Quartz!


在定义jobDetail和Trigger时我们可以指定其名称已经其所属组的名称像这样定义:

// 定义一个jobDetail
JobDetail jobDetail = JobBuilder.newJob(SimpleJob.class).withIdentity("simpleJob", "jobGroup").build();
// 定义一个触发规则每5秒触发一次总计3次
Trigger trigger = TriggerBuilder.newTrigger()
.withIdentity("simpleTriggeer", "jobTriggerGroup")
.withSchedule(SimpleScheduleBuilder.simpleSchedule()
.withIntervalInSeconds(5).withRepeatCount(3))
.build();


scheduler 执行 job 时,在调用其 execute() 方法之前会创建该类的一个新的实例,执行完毕,该实例的饮用就会被丢弃,实例会被垃圾回收。这种执行策略带来的后果就是,job 必须有一个无参的构造函数;另一个是,在 job 类中,不应该定义有状态的数据属性,因为 job 多次执行中,这些属性的值不会保留。

那么如何给 job 实例增加属性或配置呢?如何在 job 多次执行中,跟踪 job 的状态呢?答案就是 JobDataMap。我们在job加入调度之前可以将一些数据放入JobDataMap中在job执行的过程中我们就可以取出来使用。JobDataMap是map的一个实现,所以我们可以用键值对方式对其进行操作。

例如:

public class SimpleJob implements Job{

@Override
public void execute(JobExecutionContext jobContext) throws JobExecutionException {
System.out.println(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss")
.format(new Date())+"Hello Quartz!");
/*JobKey jobKey = jobContext.getJobDetail().getKey();
JobDataMap dataMap = jobContext.getJobDetail().getJobDataMap();
int num = dataMap.getInt("int");
String str = dataMap.getString("String");
boolean boo = dataMap.getBoolean("boolean");
System.err.println(num+"==="+num);*/
JobKey jobTriggerKey = jobContext.getTrigger().getJobKey();
JobDataMap triggerDataMap = jobContext.getTrigger().getJobDataMap();
Iterator<Entry<String, Object>> it = triggerDataMap.entrySet().iterator();
System.out.println(jobTriggerKey);
while (it.hasNext()) {
Entry<String, Object> entry = it.next();
Object key = entry.getKey();
Object value = entry.getValue();
System.out.println("key=" + key + " value=" + value);
}
}

}


Trigger定义

public class SimpleTrigger {

public static void main(String[] args) throws SchedulerException {
// 定义一个jobDetail
JobDetail jobDetail = JobBuilder.newJob(SimpleJob.class).withIdentity("simpleJob", "jobGroup").build();
// 定义一个触发规则每5秒触发一次总计3次
Trigger trigger = TriggerBuilder.newTrigger()
.withIdentity("simpleTriggeer", "jobTriggerGroup")
.usingJobData("int", 12)
.usingJobData("String", "哈哈哈")
.usingJobData("boolean", true)
.withSchedule(SimpleScheduleBuilder.simpleSchedule()
.withIntervalInSeconds(5).withRepeatCount(0))
.build();
//通过SchedulerFactory获取一个调度器实例
SchedulerFactory schedulerFactory = new StdSchedulerFactory();
Scheduler scheduler = schedulerFactory.getScheduler();
scheduler.scheduleJob(jobDetail, trigger);
//启动调度
scheduler.start();

}

}


结果:

log4j:WARN Please initialize the log4j system properly.
log4j:WARN See http://logging.apache.org/log4j/1.2/faq.html#noconfig for more info.
2018-03-09 11:29:30Hello Quartz!
jobGroup.simpleJob
key=String value=哈哈哈
key=int value=12
key=boolean value=true


使用CronTrigger

CronTrigger 能够提供比 SimpleTrigger 更有具体实际意义的调度方案,调度规则基于 Cron

表达式,CronTrigger

支持日历相关的重复时间间隔(比如每月第一个周一执行),而不是简单的周期时间间隔。因此,相对于SimpleTrigger而言,CronTrigger在使用上也要复杂一些。

Cron表达式

Quartz使用类似于Linux下的Cron表达式定义时间规则,Cron表达式由6或7个由空格分隔的时间字段组成,如表1所示: 表1

Cron表达式时间字段



Cron表达式的时间字段除允许设置数值外,还可使用一些特殊的字符,提供列表、范围、通配符等功能,细说如下:

●星号():可用在所有字段中,表示对应时间域的每一个时刻,例如,在分钟字段时,表示“每分钟”;

●问号(?):该字符只在日期和星期字段中使用,它通常指定为“无意义的值”,相当于点位符;

●减号(-):表达一个范围,如在小时字段中使用“10-12”,则表示从10到12点,即10,11,12;

●逗号(,):表达一个列表值,如在星期字段中使用“MON,WED,FRI”,则表示星期一,星期三和星期五;

●斜杠(/):x/y表达一个等步长序列,x为起始值,y为增量步长值。如在分钟字段中使用0/15,则表示为0,15,30和45秒,而5/15在分钟字段中表示5,20,35,50,你也可以使用*/y,它等同于0/y;

●L:该字符只在日期和星期字段中使用,代表“Last”的意思,但它在两个字段中意思不同。L在日期字段中,表示这个月份的最后一天,如一月的31号,非闰年二月的28号;如果L用在星期中,则表示星期六,等同于7。但是,如果L出现在星期字段里,而且在前面有一个数值X,则表示“这个月的最后X天”,例如,6L表示该月的最后星期五;

●W:该字符只能出现在日期字段里,是对前导日期的修饰,表示离该日期最近的工作日。例如15W表示离该月15号最近的工作日,如果该月15号是星期六,则匹配14号星期五;如果15日是星期日,则匹配16号星期一;如果15号是星期二,那结果就是15号星期二。但必须注意关联的匹配日期不能够跨月,如你指定1W,如果1号是星期六,结果匹配的是3号星期一,而非上个月最后的那天。W字符串只能指定单一日期,而不能指定日期范围;

●LW组合:在日期字段可以组合使用LW,它的意思是当月的最后一个工作日;

●井号(#):该字符只能在星期字段中使用,表示当月某个工作日。如6#3表示当月的第三个星期五(6表示星期五,#3表示当前的第三个),而4#5表示当月的第五个星期三,假设当月没有第五个星期三,忽略不触发;



C:该字符只在日期和星期字段中使用,代表“Calendar”的意思。它的意思是计划所关联的日期,如果日期没有被关联,则相当于日历中所有日期。例如5C在日期字段中就相当于日历5日以后的第一天。1C在星期字段中相当于星期日后的第一天。

Cron表达式对特殊字符的大小写不敏感,对代表星期的缩写英文大小写也不敏感。

实例如下:

public class CronTriggerDemo {

public static void main(String[] args) throws SchedulerException {
// 定义一个jobDetail
JobDetail jobDetail = JobBuilder.newJob(SimpleJob.class).withIdentity("simpleJob", "jobGroup").build();
CronTrigger cronTrigger = (CronTrigger) TriggerBuilder.newTrigger()
.withIdentity("cronTriggeer", "jobTriggerGroup")
.usingJobData("int", 12)
.usingJobData("String", "哈哈哈")
.usingJobData("boolean", true)
//每天下午1点48执行一次
.withSchedule(CronScheduleBuilder.cronSchedule("0 48  13 * * ?"))
.build();
//通过SchedulerFactory获取一个调度器实例
SchedulerFactory schedulerFactory = new StdSchedulerFactory();
Scheduler scheduler = schedulerFactory.getScheduler();
scheduler.scheduleJob(jobDetail, cronTrigger);
//启动调度
scheduler.start();
}

}


结果:

log4j:WARN Please initialize the log4j system properly.

log4j:WARN See http://logging.apache.org/log4j/1.2/faq.html#noconfig for more info.

2018-03-09 13:48:00Hello Quartz!

jobGroup.simpleJob

key=String value=哈哈哈

key=int value=12

key=boolean value=true

使用Calendar

实际任务调度中我们除了这种周期性的任务调度以外,还需要有些特殊的情况。例如每天下午1点48执行但是周五不执行,遇到这种情况就需要我们使用Calendar。下面是calendar中各个类的用法



实例如下:

public class CronTriggerWithCalendarDemo {

public static void main(String[] args) throws SchedulerException {
//通过SchedulerFactory获取一个调度器实例
SchedulerFactory schedulerFactory = new StdSchedulerFactory();
Scheduler scheduler = schedulerFactory.getScheduler();
// 定义一个jobDetail
JobDetail jobDetail = JobBuilder.newJob(SimpleJob.class).withIdentity("simpleJob", "jobGroup").build();
//定义一个Calendar
WeeklyCalendar fridayCalendar = new WeeklyCalendar();
fridayCalendar.setDayExcluded(6, true);
//注册Calendar
scheduler.addCalendar("fridayCalendar", fridayCalendar, true, true);
CronTrigger cronTrigger = (CronTrigger) TriggerBuilder.newTrigger()
.withIdentity("cronTriggeer", "jobTriggerGroup")
.modifiedByCalendar("fridayCalendar")
.usingJobData("int", 12)
.usingJobData("String", "哈哈哈")
.usingJobData("boolean", true)
//每天下午1点48执行一次
.withSchedule(CronScheduleBuilder.cronSchedule("0 48  14 * * ?"))
.build();

scheduler.scheduleJob(jobDetail, cronTrigger);
//启动调度
scheduler.start();
}


}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: