任务调度与异步执行器:
1、任务调度
时间上的调度:特定时间执行指定的操作,如生成精华文章,统计记分排名,锁定用户
资源调度:对使用资源进行控制
涉及内容:
多线程并发,运行时间规则定义,运行现场保持和恢复,线程池维护。
2、实现方式:
a、自定义多线程实现(难度太大)
b、jdk1.3开始,通过java.util.Timer和TimerTask提供了简单的调用功能,允许用户调度一个按照固定周期运行的任务。
c、jdk5.0通过java.util.concurrent新包中的若干接口,提供了方便的线程池使用。
d、使用Quarz来实现任务调度功能
注意:Spring对b,c,d三种方式都提供了支持,并不是自己实现了整个任务调度的功能,只是进行了封装,方便与spring进行整合,使用bean配置的方式,更易于程序开发。
3、Quartz概述:
3.1 功能简介:
灵活的定义触发器的调度时间表,并与任务进行关联映射。
良好的现场恢复功能。
3.2核心概念与接口:
任务:
描述:要执行的具体操作。
核心API:
Job接口:定义要执行的任务,JobExecutieonContext中保存了调度上下文中的数据:
public void execute(JobExecutionContext context);
JobDetail接口:用来描述任务的详细信息,包括Job名称,监听器,描述,还有Job的具体实现类,这样方便运行时通过反射来执行Job,
JobDetailImple:JobDetail实现类
触发器:
描述:触发任务执行的规则,多为时间规则。
核心API:
Trigger类:定义触发任务执行的时间规则,主要用器两个子类:
SimpleTrigger类:触发一次,或者按照固定间隔周期性执行
CronTrigger类:复杂的时间触发,通过Cron表达式来定义,支持日历相关的时间间隔规则,而不是简单的周期性间隔。
Calender类:一些特定日历的时间点的集合
调度器:
描述:quartz运行的独立容器,任务调度时,相关的任务,触发器,日历都需要注册到调度器中,运行时通过调度器来调度执行。调度器中的对象通过组和名称来确定唯一性。
核心API:
Scheduler接口:使用Scheduler中的接口,通过组和名称可以访问到调度器内的任务和触发器,并实现他们之间的绑定后,当触发器触发时,任务就会执行。
SchdeulerFactory类:调度器工厂用来创建一个调度器,每个调度器都拥有自己的SchedulerContext,触发器和任务都可以访问SchedulerContext中的信息
线程池:
任务通过共享线程池内的线程提高运行效率。
其他API:
Quartz提供了构建器风格的api,对于调度器中的实体,都可以通过对应的构建器进行实例化,如:
JobBuilder:用来构建JobDetail实体对象:
JobDetail jobDetail=JobBuilder.newJob(SimpleJob.class)
.withIdentity("MyJob1", "MyJobs")
.build();//构建任务
TriggerBuilder:用来构建Trigger对象:
SimpleTrigger trigger=TriggerBuilder.newTrigger()
.withIdentity("trigger1", "myTriggers").startNow()
.withSchedule(SimpleScheduleBuilder.repeatSecondlyForTotalCount(10))
.build();
ScheduleBuilder:用来构建一个计划,与触发器绑定:
SimpleScheduleBuilder.repeatSecondlyForTotalCount(10)
创建一个调度器,并调度任务:
SchedulerFactory fac=new StdSchedulerFactory();
Scheduler scheduler=fac.getScheduler();
scheduler.scheduleJob(jobDetail, trigger);
scheduler.start();
注意:
一个任务可以绑定多个触发器,一个触发器只能对应一个任务。
每个调度器(scheduler)中都有一个调度上下文,(schedulContext),其中的信息为调度其中的对象所共有共享。任务 (jobDetail)和触发器(Trigger)除共享schedulerContext中的数据外,本身都拥有一个JobDataMap对象,用来存放任务或者触发器本身的数据,对于无状态(没有实现StatfulJob接口)的任务还有触发器,在每次执行过程中都可以访问JobDataMao内的数据,但是执行中对JobDataMap中的数据修改,不会影响下次的执行,即他们拥有的是自己JobDataMap对象的复制对象。
Cron表达式:用来构建复杂的CronTrigger,Cron表达式有6或者7位从左到右的字符组成,有空格隔开:
Cron表达式时间字段
位置(从左到右)
|
表示时间 |
允许值范围
|
允许特殊字符 |
1
|
秒
|
0-59
|
*,-/
|
2
|
分钟 |
0-59
|
*,-/
|
3
|
小时 |
0-23
|
*,-/
|
4
|
日期
|
1-31
|
*,-/?LWC
|
5
|
月份
|
1-12
|
*,-/ |
6
|
星期
|
1-7(7是星期六)
|
*,-/?LC#
|
7
|
年份
|
空值或1970-2099 |
*-,/ |
特殊字符的意义(
在对应的字段的时间范围内):
*:
对应时间范围的每一个时刻,如在分钟字段中,则表示“每分钟”
?:无意义,占位符,
只能用在日期和星期字段中
-:在对应时间域中表示一个范围,如小时中12-13表示12点到13点钟
,:表示一个列表,如MON,WEN比表示星期一和星期三
/:x/y表示一个等步长序列,x为起始值,y为步长
L:Last的意思,
只在日期和星期中使用,最后月中最后一天,或者一周中最后一天,
一周内最后一天是星期六,值是7。L前面有数值时表示,最后第几天,如5L
W:
只能在日期字段内,表示最近的工作日,如15W表示该月内15号最近的工作日,匹配不能跨月,有连个最近天时往后推。
LW:
日期字段中,当月最后一个工作日。
#:
星期字段中使用,当月某一个工作日,如6#3,6是星期五,表示当月第3个星期五,当月如果没有则不处罚。
C:
只在日期和星期字段中使用,关联某一个日期或星期,如日期字段中10C,表示当月10号后的第一天,星期字段中2C表示星期一后的第一天。
Cron表达式对特殊字符的大小写不敏感,对代表星期的缩写英文大小写也不敏感。
Cron表示式示例
表示式 |
说明 |
"0 0 12 * * ? " |
每天12点运行 |
"0 15 10 ? * *" |
每天10:15运行 |
"0 15 10 * * ?" |
每天10:15运行 |
"0 15 10 * * ? *" |
每天10:15运行 |
"0 15 10 * * ? 2008" |
在2008年的每天10:15运行 |
"0 * 14 * * ?" |
每天14点到15点之间每分钟运行一次,开始于14:00,结束于14:59。 |
"0 0/5 14 * * ?" |
每天14点到15点每5分钟运行一次,开始于14:00,结束于14:55。 |
"0 0/5 14,18 * * ?" |
每天14点到15点每5分钟运行一次,此外每天18点到19点每5钟也运行一次。 |
"0 0-5 14 * * ?" |
每天14:00点到14:05,每分钟运行一次。 |
"0 10,44 14 ? 3 WED" |
3月每周三的14:10分到14:44,每分钟运行一次。 |
"0 15 10 ? * MON-FRI" |
每周一,二,三,四,五的10:15分运行。 |
"0 15 10 15 * ?" |
每月15日10:15分运行。 |
"0 15 10 L * ?" |
每月最后一天10:15分运行。 |
"0 15 10 ? * 6L" |
每月最后一个星期五10:15分运行。 |
"0 15 10 ? * 6L 2007-2009" |
在2007,2008,2009年每个月的最后一个星期五的10:15分运行。 |
"0 15 10 ? * 6#3" |
每月第三个星期五的10:15分运行。 |
日历使用:
实际调度中,有时不能不变的按照特定周期调度人物,必须考虑到一些特殊的日期,要排除,则需使用Quartz中的日历,某些特定时间的集合,
Calendar提供了一些常用的日历实现类,来表示特定的日期:
3.3、任务调度信息存储
一般情况下,任务的调度信息存储在内存中,如调度次数,第几次等调度, JobDataMap中的数据等相关信息。这样数据访访问快,但是由于数据没有持久化保存,当系统崩溃时,所有运行时信息丢失,调度现场无法还原。
配置任务调度信息的保存策略:
4、Spring集成Quartz
Spring为创建JobDetail、Scheduler、Trigger等调度器实体,提供了便利的FactoryBean,方便Spring容器的管理,并提供了一些工具类,
可以将Spring中的Bean封装成任务,对Quartz进行了封装,能以更具Spring风格的使用Quartz。
主要有两个方面的支持:
1、提供良好的BeanFactory类,在Spring环境中创建Quartz任务调度中对应的组件对象,
并结合Spring容器的生命周期进行调度的启动和停止。
2、为Quartz重要的组件对象提供更具Bean风格的扩展类。
Spring对Quartz的扩展
JobDetailBean:对JobDetail的扩展,更具Bean风格的扩展。直接创建JobDetail只能通过爱参数的构造函数。
全称:org.springframework.scheduling.quartz.JobDetailBean。
常见属性配置:
jobClass:Job接口的任务类,class类型
beanName:默认为bean的id名,对应任务名,不指定组则是默认组
JobDataAsMap:map类型,任务对应提供数据的JobDataMap
applicationContextJobDataKey:是否将spring的applicationContext保存到任务的JobDataMap中,给属性指定key,无该属性在不保存。
JobListenNames:String数组类型,指定注册在Scheduler中的jobListeners名臣。
MethodInvokingJobDetailFactoryBean:
生成任务的BeanFactory,能够方便的将Spring中的bean的某一个方法,封装成满足Quartz要求的Job,
全称:
org.springframework.scheduling.quartz.
MethodInvokingJobDetailFactoryBean
常见属性配置:
targetObject:引用哪个bean
targetMethod:指定bean的哪个方法
concurrent:任务是有状态任务,还是无状态任务
SimpleTriggerBean
:SimpleTrigger的扩展类,在Spring以bean的方式记性配置。
全称:
org.springframework.scheduling.quartz.SimpleTriggerBean
常见属性配置:
jobDetail:对应的Spring中的任务
jobDataAsMap:trigger中的jobDataMap提供值,map类型
startDelay:延时多少时间开始触发。
CronTriggerBean
:CronTrigger的扩展
全称:
org.springframework.scheduling.quartz.
CronTriggerBean
常见属性配置:
jobDetail:对应的Spring中的任务
jobDataAsMap:trigger中的jobDataMap提供值,map类型
cronExpression:cron表达式
SchedulerFactoryBean
:用来创建Quartz的调度器。
全称:
org.springframework.scheduling.quartz.
CronTriggerBean
主要功能:
1、以更具bean风格的方式,创建Scheduler,并提供配置信息
2、让Scheduler和Spring容器的生命周期建立关联,相生相息
3、通过属性配置方式替换Quartz的zisheg
常见配置:
JobDetails:类型为JobdDetailBean[],往调度器里面注册的JobDetail
triggers:类型TriggerBean[],往调度器内注册trigger
shedulerContextAsMap:map类型,往SchedulerContext内设置数据
autoStartup:
SchedulerFactoryBean初始化后是否马上启动Scheduler,默认true
startupDelay:
SchedulerFactoryBean初始化后,延时多少启动
Scheduler。
quartzProperties:Properties类型,覆盖Quartz的默认配置
configLocaion:显示执行quartz的配置文件
注意:静态变量是ClassLoader级别的,当Web应用程序停止时,静态变量会从JVM中清楚
,但是线程则是JVM级别的,如果用户在Web应用中启动了一个线程,这个线程的生命周期不会和Web应用程序保持同步,只要JVM不关闭,即使关闭了Web应用,线程依然是活跃。
当我们手动使用JDK Timer或者Quart进行任务调度时,在Web引用关闭时,要手动停止调度。
Spring为我们提供了用于创建Quartz Scheduler和JDK Timer基础设施的Factory,可以保证Quartz和JDK Timer调度线程在Spring 容器关闭时自动停止。