定时器3——定时框架Quartz2

1. 资源SchedulerFactory

1.1 介绍

        Quartz以模块方式架构,因此,要使它运行,几个组件必须很好的咬合在一起,幸运的是,已经有了一些现存的助手可以完成这些工作,所有的Scheduler实例由SchedulerFactory创建。

        Quartz的三个核心概念:调度器、任务、触发器,三者之间的关系

SchedulerFactory ——> Scheduler ——> Trigger/job

        SchedulerFactory 接口,有两个子类,一个是StdSchedulerFactory,另一个是DirectSchedulerFactory,我们之前用的都是StdSchedulerFactory。

        一个作业,比较重要的三要素是Scheduler、JobDetail、Trigger,而Trigger对于Job而言就好比一个驱动器,没有触发器来定时驱动作业,作业就无法运行,对于Job而言,一个Job可以对应多个Trigger,单对于Trigger而言,一个Trigger只能对应一个Job,所以一个Trigger只能被指派给一个job,所以如果我们需要一个复杂的触发计划,可以创建多个Trigger并指派他们给同一个job。

1.2 Scheduler的创建方式

1.2.1 StdSchedulerFactory

        Quartz默认的SchedulerFactory。

1. 使用一组参数(java.util.Properties)来创建和初始化Quartz调度器。

2. 配置参数一般存储在quartz.properties文件中。

3. 调用getScheduler方法就能创建和初始化调度器对象。例如:

// Scheduler scheduler = StdSchedulerFactory.getDefaultScheduler();
SchedulerFactory s = new StdSchedulerFactory();
Scheduler scheduler = s.getScheduler();

注意:看源码知道,StdSchedulerFactory.getDefaultScheduler();内部实现就是用的该方式。

1.2.2 Scheduler的API

1. 获取调度器开始时间

Date startDate = scheduler.scheduleJob(jobDetail, trigger);

2. 启动任务调度

scheduler.start();

3. 任务调度挂起、暂停

scheduler.standby();

4. 关闭任务调度

scheduler.shutdown();

scheduler.shutdown(true):表示等待所有正在执行的job执行完毕之后,再关闭Scheduler

scheduler.shutdown(false):表示直接关闭Scheduler

1.3 DirectSchedulerFactory

        DirectSchedulerFactory是对SchedulerFactory的直接实现,通过它可以直接构建Scheduler、Threadpool等。

DirectSchedulerFactory instance = DirectSchedulerFactory.getInstance();
Scheduler scheduler1 = instance.getScheduler();

2. Quartz.properties配置文件

默认路径:quartz-2.3.0中的org.quartz.properties

 注意:如果不想用默认的配置文件,我们也可以在资源目录下新建quartz.properties配置文件,在该文件下写自己的配置信息

2.1 配置文件详解

# Default Properties file for use by StdSchedulerFactory
# to create a Quartz Scheduler Instance, if a different
# properties file is not explicitly specified.
#

org.quartz.scheduler.instanceName: DefaultQuartzScheduler
org.quartz.scheduler.rmi.export: false
org.quartz.scheduler.rmi.proxy: false
org.quartz.scheduler.wrapJobExecutionInUserTransaction: false

org.quartz.threadPool.class: org.quartz.simpl.SimpleThreadPool
org.quartz.threadPool.threadCount: 10
org.quartz.threadPool.threadPriority: 5
org.quartz.threadPool.threadsInheritContextClassLoaderOfInitializingThread: true

org.quartz.jobStore.misfireThreshold: 60000

org.quartz.jobStore.class: org.quartz.simpl.RAMJobStore

2.1.1 调度器属性

1. org.quartz.scheduler.instanceName:用来区分特定的调度器实例,可以按照功能用途给调度器起名字。

2. org.quartz.scheduler.instanceId:也是用来区分调度器实例的,允许是任何的字符串,但是这个值必须在所有的调度器实例中是唯一的,尤其在一个集群环境中,作为集群的唯一key。

注意:如果想Quartz自动生成该值,可以将其设置成AUTO。

例如: org.quartz.scheduler.instanceId:AUTO

2.1.2 线程池属性

1. threadCount:处理job的线程个数,至少为1,但是最多的话最好不要超过100个,在多数机器上超过100个就显得相当不实用,特别是在job执行时间较长的情况下。

2. threadPriority:线程的优先级, 优先级高的线程比优先级的线程先得到执行。最小为1,最大为10,默认为5

3. threadPool.class:一个实现了org.quartz.ThreadPool接口的类,Quartz自带的线程池实现类是org.quartz.smpl.SimpleThreadPool

2.1.3 作业存储设置

描述了在调度器实例的生命周期中,Job和Trigger信息是如何被存储的

org.quartz.jobStore.class: org.quartz.simpl.RAMJobStore

2.1.4 插件配置

满足特定需求用到的Quartz插件的配置

2. 监听器

        Quartz的监听器用于当任务调度中,你所关注事件发生时,能够及时获取这一事件通知。类似于任务执行过程中的邮件、短信提醒。

        Quartz监听器主要有JobListener、TriggerListener、SchedulerListener三种,分别表示任务、触发器、调度器对应的监听器三者使用方式类似。

2.1 全局监听器

全局监听器能接收到所有的Job/Trigger 的事件通知

// 创建一个全局的监听器
scheduler.getListenerManager().addJobListener(new MyJobListener(),EverythingMatcher.allJobs());

2.2 局部监听器

非全局的监听器只能接收到在其上注册的job或trigger的事件,不在其注册的job或trigger则 不会进行监听。

// 创建一个局部监听器
scheduler.getListenerManager().addJobListener(new MyJobListener(),KeyMatcher.keyEquals(JobKey.jobKey("job1", "group1")));

2.3 JobListener

        任务调度过程中,与任务Job相关的事件包括:job开始要执行的提示,job执行完成的提示灯

2.3.1 JobListener接口中的方法与作用

1. getName():用于获取JobListener的名称

2. jobToBeExecuted(JobExecutionContext context):Scheduler在jobDetail将要被执行时调用这个方法

3. jobExecutionVetoed(JobExecutionContext context):Scheduler在jobDetail即将被执行,但又被TriggerListener否决时会调用该方法。

4. jobWasExecuted():Scheduler在JobDetail被执行之后调用该方法。

2.3.2 自定义一个Job监听器

1. 创建监听器类

package cn.bjc.quartz.listener;

import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
import org.quartz.JobListener;

public class MyJobListener implements JobListener{

	@Override
	public String getName() {
		String name = this.getClass().getSimpleName();
		System.out.println("name = " + name);
		return name;
	}

	@Override
	public void jobToBeExecuted(JobExecutionContext context) {
		String name = context.getJobDetail().getKey().getName();
		System.out.println("Job的名称是:" + name + "   Scheduler在jobDetail将要被执行时调用的方法。");
	}

	@Override
	public void jobExecutionVetoed(JobExecutionContext context) {
		System.out.println("xxx");
	}

	@Override
	public void jobWasExecuted(JobExecutionContext context, JobExecutionException jobException) {
		System.out.println("yyy");
	}

}

2. 添加监听器

2.1 添加一个全局的监听器

在scheduler.start();之前加上如下代码,EverythingMatcher.allJobs()表示所有的job

scheduler.getListenerManager().addJobListener(new MyJobListener(),EverythingMatcher.allJobs());

2.2 添加一个局部监听器,监听指定的job

scheduler.getListenerManager().addJobListener(new MyJobListener(),KeyMatcher.keyEquals(JobKey.jobKey("job1", "group1")));

完整的调用代码:

package cn.bjc.quartz.main;

import java.util.Date;

import org.quartz.CronScheduleBuilder;
import org.quartz.JobBuilder;
import org.quartz.JobDetail;
import org.quartz.JobKey;
import org.quartz.Scheduler;
import org.quartz.Trigger;
import org.quartz.TriggerBuilder;
import org.quartz.impl.StdSchedulerFactory;
import org.quartz.impl.matchers.EverythingMatcher;
import org.quartz.impl.matchers.KeyMatcher;

import cn.bjc.quartz.job.HelloJobListener;
import cn.bjc.quartz.listener.MyJobListener;

public class JobListenerDemo {

	public static void main(String[] args) throws Exception {
		Scheduler scheduler = StdSchedulerFactory.getDefaultScheduler();
		// 2. 任务实例(JobDetail),通过JobBuilder创建
		JobDetail jobDetail = JobBuilder.newJob(HelloJobListener.class)
							.withIdentity("job1", "group1")
							.usingJobData("msg", "日志打印")
							.usingJobData("count", 0)
							.build();
		// 3. 触发器(Trigger)
		Trigger trigger = TriggerBuilder.newTrigger()
							.withIdentity("trigger1", "group1")
							.startNow()
							.withSchedule(CronScheduleBuilder.cronSchedule("* * * * * ?"))	// 日历每秒执行
							.build();
		
		Date startDate = scheduler.scheduleJob(jobDetail, trigger);
		
		// 创建一个全局的监听器
		// scheduler.getListenerManager().addJobListener(new MyJobListener(),EverythingMatcher.allJobs());
		
		// 创建一个局部监听器
		scheduler.getListenerManager().addJobListener(new MyJobListener(),KeyMatcher.keyEquals(JobKey.jobKey("job1", "group1")));
		
		// 启动
		scheduler.start();
	}

}

2.4 TriggerListener

        任务调度过程中,与触发器Trigger相关的事件包括:触发器触发、触发器未正常触发、触发器完成等。

2.4.1 TriggerListener接口定义的方法

1. getName():用于获取触发器名称

2. triggerField(Trigger trigger,JobExecutionContext context):当与监听器相关联的Trigger被触发,Job上的execute方法将被执行时,Scheduler就调用该方法。

3. vetoJobExecution(Trigger trigger,JobExecutionContext context):在Trigger触发后,job将要被执行时由Scheduler调用这个方法,TriggerListener给了一个选择去否决Job的执行。假如这个方法返回true,这个Job将不会为此次Trigger触发而得到执行。

4. triggerMisfired(Trigger trigger):Scheduler调用这个方法是在Trigger错过触发时,你应该关注此方法中持续时间长的逻辑;在出现许多错过触发的Trigger时,长逻辑会导致骨牌效应,所以,你应当尽量的保持这上方法尽量的小。

5. triggerComplete(Trigger trigger):Trigger被触发并且完成了Job的执行时,Scheduler调用这个方法。

2.4.2 自定义一个TriggerListener监听器

1. 创建监听器

MyTriggerListener.java

package cn.bjc.quartz.listener;

import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
import org.quartz.JobListener;
import org.quartz.Trigger;
import org.quartz.Trigger.CompletedExecutionInstruction;
import org.quartz.TriggerListener;

public class MyTriggerListener implements TriggerListener{

	@Override
	public String getName() {
		String name = this.getClass().getSimpleName();
		System.out.println("触发器的名称是:" + name);
		return name;
	}

	@Override
	public void triggerFired(Trigger trigger, JobExecutionContext context) {
		String name = trigger.getKey().getName();
		System.out.println(name + "被触发了!");
	}

	@Override
	public boolean vetoJobExecution(Trigger trigger, JobExecutionContext context) {
		String name = trigger.getKey().getName();
		System.out.println(name + "没有被触发!");
		return true;  // true:表示不会执行job的方法。
	}

	@Override
	public void triggerMisfired(Trigger trigger) {
		String name = trigger.getKey().getName();
		System.out.println(name + "错过触发!");
	}

	@Override
	public void triggerComplete(Trigger trigger, JobExecutionContext context,
			CompletedExecutionInstruction triggerInstructionCode) {
		String name = trigger.getKey().getName();
		System.out.println(name + "完成之后触发!");
	}

}

2. 添加监听器

2.1 添加一个全局监听器

// 创建并注册一个全局TriggerListener
scheduler.getListenerManager().addTriggerListener(new MyTriggerListener(),EverythingMatcher.allTriggers());

2.2 添加一个局部监听器

// 创建并注册一个局部TriggerListener
scheduler.getListenerManager().addTriggerListener(new MyTriggerListener(), KeyMatcher.keyEquals(TriggerKey.triggerKey("trigger1")));

完整的调用:

package cn.bjc.quartz.main;

import java.util.Date;
import java.util.concurrent.ScheduledFuture;

import org.quartz.CronScheduleBuilder;
import org.quartz.JobBuilder;
import org.quartz.JobDetail;
import org.quartz.JobKey;
import org.quartz.Scheduler;
import org.quartz.Trigger;
import org.quartz.TriggerBuilder;
import org.quartz.TriggerKey;
import org.quartz.impl.StdSchedulerFactory;
import org.quartz.impl.matchers.EverythingMatcher;
import org.quartz.impl.matchers.KeyMatcher;

import cn.bjc.quartz.job.HelloJobListener;
import cn.bjc.quartz.listener.MyJobListener;
import cn.bjc.quartz.listener.MyTriggerListener;

public class TriggerListenerDemo {

	public static void main(String[] args) throws Exception {
		Scheduler scheduler = StdSchedulerFactory.getDefaultScheduler();
		// 2. 任务实例(JobDetail),通过JobBuilder创建
		JobDetail jobDetail = JobBuilder.newJob(HelloJobListener.class)
							.withIdentity("job1", "group1")
							.usingJobData("msg", "日志打印")
							.usingJobData("count", 0)
							.build();
		// 3. 触发器(Trigger)
		Trigger trigger = TriggerBuilder.newTrigger()
							.withIdentity("trigger1", "group1")
							.startNow()
							.withSchedule(CronScheduleBuilder.cronSchedule("* * * * * ?"))	// 日历每秒执行
							.build();
		
		Date startDate = scheduler.scheduleJob(jobDetail, trigger);
		
		// 创建并注册一个全局TriggerListener
		//scheduler.getListenerManager().addTriggerListener(new MyTriggerListener(),EverythingMatcher.allTriggers());
		
		// 创建并注册一个局部TriggerListener
		scheduler.getListenerManager().addTriggerListener(new MyTriggerListener(), KeyMatcher.keyEquals(TriggerKey.triggerKey("trigger1","group1")));
		
		// 启动
		scheduler.start();
	}

}

2.5 SchedulerListener监听器

        SchedulerListener会在Scheduler的生命周期中关键事件发生时被调用,与Scheduler有关的事件包括:增加一个job/trigger,删除一个job/trigger,scheduler发生严重错误的时候,关闭scheduler。

2.5.1 SchedulerListener接口的方法

1. jobScheduler(Trigger trigger):用于部署JobDetail时调用

2. jobUnscheduled(String triggerName,String triggerGroup):用于卸载JobDetail时调用

3. triggerFinalized(Trigger trigger):当一个trigger来到了再也不会触发的状态的时候调用这个方法。除非这个job已设置成了持久性,否则它就会从Scheduler中移除。

4. triggersPaused(String triggerName,String triggerGroup):Scheduler调用这个方法是发生在一个Trigger或trigger组被暂停的时候。假如Trigger组的话,triggerName参数将为null。

5. triggersResumed(String triggerName,String triggerGroup):Scheduler调用这个方法是发生在一个trigger或trigger组被暂停时。加入是trigger组的话,triggerName参数将为null

6. jobsPaused(String triggerName,String triggerGroup):当一个或一组job被暂停的时候调用

7. jobsResumed(String triggerName,String triggerGroup):当一个或一个组job从暂停上恢复时调用。加入是job组,jobName参数将为null。

8. schedulerError(String msg,SchedulerException cause):在Scheduler正常运行期间,产生一个严重错误的时候调用

9. schedulerStarted():当scheduler开启的时候调用

10. schedulerInStandbyMode():当scheduler处于StandBy模式时,调用该方法。

11. schedulerShutdown():当scheduler停止时调用

12. schedulingDataCleared():当scheduler中的数据被清除的时候调用

2.5.2 Scheduler监听器的使用

1. 自定义Scheduler监听器

package cn.bjc.quartz.listener;

import org.quartz.JobDetail;
import org.quartz.JobKey;
import org.quartz.SchedulerException;
import org.quartz.SchedulerListener;
import org.quartz.Trigger;
import org.quartz.TriggerKey;

public class MySchedulerListener implements SchedulerListener{

	@Override
	public void jobScheduled(Trigger trigger) {
		String name = trigger.getKey().getName();
		System.out.println(name + "部署的时候调用!");
	}

	@Override
	public void jobUnscheduled(TriggerKey triggerKey) {
		String name = triggerKey.getName();
		System.out.println(name + "卸载JobDetail时调用!");
	}

	@Override
	public void triggerFinalized(Trigger trigger) {
		String name = trigger.getKey().getName();
		System.out.println(name + "被移除调用!");
	}

	@Override
	public void triggerPaused(TriggerKey triggerKey) {
		String name = triggerKey.getName();
		System.out.println(name + "正在被暂停!");
	}

	@Override
	public void triggersPaused(String triggerGroup) {
		System.out.println("触发器组" + triggerGroup + "正在被暂停!");
	}

	@Override
	public void triggerResumed(TriggerKey triggerKey) {
		String name = triggerKey.getName();
		System.out.println(name + "正在被恢复!");
	}

	@Override
	public void triggersResumed(String triggerGroup) {
		System.out.println("触发器组" + triggerGroup + "正在被恢复!");
	}

	@Override
	public void jobAdded(JobDetail jobDetail) {
		String name = jobDetail.getKey().getName();
		System.out.println(name + "添加工作任务的时候调用!");
	}

	@Override
	public void jobDeleted(JobKey jobKey) {
		String name = jobKey.getName();
		System.out.println(name + "删除工作任务的时候调用!");
	}

	@Override
	public void jobPaused(JobKey jobKey) {
		String name = jobKey.getName();
		System.out.println(name + "暂停工作任务的时候调用!");
	}

	@Override
	public void jobsPaused(String jobGroup) {
		System.out.println("job组" + jobGroup + "暂停的时候调用!");
	}

	@Override
	public void jobResumed(JobKey jobKey) {
		System.out.println("工作任务恢复!");
	}

	@Override
	public void jobsResumed(String jobGroup) {
		System.out.println("工作组任务恢复!");
	}

	@Override
	public void schedulerError(String msg, SchedulerException cause) {
		System.out.println("调用出错,错误信息是:" + msg + "   具体错误原因是:" + cause.getUnderlyingException());
	}

	@Override
	public void schedulerInStandbyMode() {
		System.out.println("调度器被挂起模式的时候调用!");
	}

	@Override
	public void schedulerStarted() {
		System.out.println("调度器开启的时候调用!");
	}

	@Override
	public void schedulerStarting() {
		System.out.println("调度器正在开启的时候调用!");
	}

	@Override
	public void schedulerShutdown() {
		System.out.println("调度器关闭的时候调用!");
	}

	@Override
	public void schedulerShuttingdown() {
		System.out.println("调度器正在关闭的时候调用!");
	}

	@Override
	public void schedulingDataCleared() {
		System.out.println("当scheduler中的数据被清除的时候调用!");
	}

}

2. 添加监听

scheduler.getListenerManager().addSchedulerListener(mySchedulerListener);

调用代码:

package cn.bjc.quartz.main;

import org.quartz.JobBuilder;
import org.quartz.JobDetail;
import org.quartz.Scheduler;
import org.quartz.SimpleScheduleBuilder;
import org.quartz.Trigger;
import org.quartz.TriggerBuilder;
import org.quartz.impl.StdSchedulerFactory;

import cn.bjc.quartz.job.HelloJobListener;
import cn.bjc.quartz.listener.MySchedulerListener;

public class SchedulerListenerDemo {

	public static void main(String[] args) throws Exception {
		Scheduler scheduler = StdSchedulerFactory.getDefaultScheduler();
		// 2. 任务实例(JobDetail),通过JobBuilder创建
		JobDetail jobDetail = JobBuilder.newJob(HelloJobListener.class)
							.withIdentity("job1", "group1")
							.usingJobData("msg", "日志打印")
							.usingJobData("count", 0)
							.build();
		// 3. 触发器(Trigger)
		Trigger trigger = TriggerBuilder.newTrigger()
							.withIdentity("trigger1", "group1")
							.startNow()
							.withSchedule(SimpleScheduleBuilder.repeatSecondlyForever(5)
									.withRepeatCount(2))	// 5秒后重复执行,只重复执行4次
							.build();
		
		scheduler.scheduleJob(jobDetail, trigger);
		MySchedulerListener mySchedulerListener = new MySchedulerListener();
		// 注册监听器
		scheduler.getListenerManager().addSchedulerListener(mySchedulerListener);
		// 移除监听
		// scheduler.getListenerManager().removeSchedulerListener(mySchedulerListener);
		
		// 启动
		scheduler.start();
		Thread.sleep(8000);
		scheduler.shutdown();
	}

}
发布了128 篇原创文章 · 获赞 6 · 访问量 3194

猜你喜欢

转载自blog.csdn.net/weixin_43318134/article/details/103828248