quartz是一种任务调度框架。
quartz调度的核心元素以及在于spring整合时的存在形式:
(!!!核心元素比较多,都是概念性的东西,建议大家一定仔细看,第一遍看不懂没关系,浏览一遍后,结合自己写的demo回过头来细细地看就会清晰很多。)
1、Job:是一个接口,只有一个方法void execute(JobExecutionContext context),开发者在实现该接口的execute方法中编写所需要的定时任务,JobExecutionContext类提供了调度上下文的各种信息。Job运行时的信息保存在JobDataMap实例中。实现接口的任务,默认是无状态的,若要将Job设置成有状态的,在quartz中是给实现的Job添加@DisallowConcurrentExecution注解(以前是实现StatefulJob接口,现在已被Deprecated)。在与spring结合中可以在spring配置文件的jobDetail中配置concurrent参数。
2、JobDetail:用来描述Job实现类及其他相关的静态信息,如Job名字、描述、关联监听器等信息。Quartz每次调度Job时,都创建一个Job实例,所以它不直接接收一个Job实例,相反它接收一个Job实现类。在spring中有JobDetailFactoryBean和MethodInvokingJobDetailFactoryBean两种实现,如果任务调度只需要执行某个类的某个方法,就可以通过MethodInvokingJobDetailFactoryBean来调用。
3、Trigger:触发器,是一个类,描述触发Job执行的时间触发规则。(即用于定义任务调度的时间规则),有SimpleTrigger、CronTrigger、DateIntervalTrigger和NthIncludeDayTrigger,前两个是主要的,其中CronTrigger用的比较多。当且仅当需调度一次或者以固定时间间隔周期执行调度,SimpleTrigger是最适合的选择;而CronTrigger则可以通过Cron表达式定义出各种复杂的时间规则的调度方案。在spring中封装在CronTriggerFactoryBean中。(注:Cron表达式专门开了一片文章,点击此处跳转)
4、Calendar:它是一些日历特定时间点的集合。他与java.util.Calendar不同,util那个代表一个日历的时间点,可以简单地将quartz那个看做util那个的集合。一个trigger可以包含多个Calendar,以便排除或包含某些时间点。
假设,我们安排每周一早上10:00执行任务,但是如果碰到法定的节日则不执行任务,这些就需要在Trigger触发机制的基础上使用Calendar进行定点排除。针对不同时间段类型,Quartz在org.quartz.impl.calendar包下提供了若干个Calendar的实现类,如AnnualCalendar、MonthlyCalendar、WeeklyCalendar分别针对每年、每月和每周进行定义。
5、Scheduler:任务调度器,实际执行任务的控制器,代表一个Quartz的独立运行容器,Trigger和JobDetail可以注册到Scheduler中,两者在Scheduler中拥有各自的组及名称,组及名称是Scheduler查找定位容器中的某一对象依据,Trigger的组及名称必须唯一,JobDetail的组及名称也必须唯一(但可以和Trigger的组和名称相同,因为他们不同类型的)。Scheduler定义了多个接口方法,允许外部通过组及名称访问和控制容器中Trigger和JobDetail。在spring中通过SchedulerFactoryBean封装起来。
Scheduler可以被Trigger绑定到某一个JobDetail中,这样当Trigger触发时,对应的Job就被执行。一个Job可以对应多个Trigger,但一个Trigger只能对应一个Job。可以通过SchedulerFactory创建一个Scheduler实例。Scheduler拥有一个SchedulerContext,他类似于ServletContext,保存着Scheduler上下文信息,Job和Trigger都可以访问SchedulerContext内的信息。SchedulerContext内部通过一个Map,以键值对的方式维护这些上下文数据,SchedulerContext为保存和获取数据提供了多个put()和geiXxx()的方法。可以通过Scheduler#getContext()获取对应的SchedulerContext实例。
6、ThreadPool
demo:
/** * @description 任务调度测试任务 * @author: gaobh * @date: 2018/3/21 15:58 * @version: v1.0 */ public class HelloQuartz implements Job { @Override public void execute(JobExecutionContext context) throws JobExecutionException { JobDetail detail = context.getJobDetail(); String name = detail.getJobDataMap().getString("name"); System.out.println("say hello to " + name + " at " + new Date()); } }
上面这段代码就是一个Job的实现类,需要调度的任务。
public static void main(String[] args) { try { //创建scheduler:调度器。所有的调度都是由他控制 Scheduler scheduler = StdSchedulerFactory.getDefaultScheduler(); //定义一个Trigger 触发的条件 Trigger trigger = newTrigger().withIdentity("trigger1", "group1") //一旦加入scheduler,立即生效 .startNow() //使用SimpleTrigger .withSchedule(simpleSchedule() //每隔一秒执行一次 .withIntervalInSeconds(2) //一直执行,奔腾到老不停歇 .repeatForever()) .build(); //定义一个JobDetail //定义Job类为HelloQuartz类,这是真正的执行逻辑所在 JobDetail job = newJob(HelloQuartz.class) //定义name/group .withIdentity("job1", "group1") //定义属性 .usingJobData("name", "quartz") .build(); //加入这个调度 scheduler.scheduleJob(job, trigger); //启动 scheduler.start(); //运行一段时间后关闭 Thread.sleep(10000); scheduler.shutdown(true); } catch (Exception e) { e.printStackTrace(); } }
上面一段代码可以结合之前的quartz的几个核心元素结合着看,会清晰很多:
- 首先,创建一个调度器Scheduler,所有的调度都是由他来控制
Scheduler scheduler = StdSchedulerFactory.getDefaultScheduler();
- 定义一个Trigger触发器,将一些触发条件及基础信息(即组和名称)设置进来,如上的解释,此处就不做说明了,详细的说明结合第一块核心元素的讲解。
- 定义一个Job类为HelloQuartz.class。
- 最后,就是将之前准备的一些东西注册到调度器中,并启动。
scheduler.scheduleJob(job, trigger);
scheduler.start();
运行结果:任务每隔两秒调度一次,10秒后停止。
参考文章:
这里主要讲解的只是一个简单的实例,我还写了很多其他quartz的学习博客。
quartz学习使用心得(2)之quartz.properties