Lesson45_Quartz

36 篇文章 0 订阅
5 篇文章 0 订阅

Quartz

Quartz概念

基本概念

起源

Quartz是OpenSymphony开源组织在Job scheduling(任务调度)领域又一个开源项目
它可以与J2EE或J2SE应用程序相结合,也可以单独使用

特点

Quartz是开源且具有丰富特性的“任务调度库”,能够集成于任何的java应用,小到独立的应用,大至电子商业系统
quartz都能创建亦简单亦复杂的调度,以执行上十、上百,甚至上万的任务
任务job被定义为标准的java组件,能够执行任何你想要实现的功能
quartz调度框架包含许多企业级的特性,如JTA事务、集群的支持。

总结

简而言之,quartz就是基于java实现的任务调度框架,用于执行你想要执行的任何任务。

官方网站

http://www.quartz-scheduler.org/

Quartz运行环境

  • Quartz可以运行嵌入在另一个独立式应用程序
  • Quartz可以在应用程序服务器(或servlet容器)内被实例化,并且参与事务
  • Quartz可以作为一个独立的程序运行(其自己的Java虚拟机内),可以通过RMI使用
  • Quartz可以被实例化,作为独立的项目集群(负载均衡和故障转移功能),用于作业的执行

Quartz设计模式(官方示例)

  • Builder模式
    // 任务
    JobbDetail job = newJob(MyJob.class).withIdentity("job1","group1").build();
    // 触发器
    Trigger trigger = newTrigger().withIdentity("trigger1","group1").startNow()
    .withSchedule(simpleSchedule().withIntervalInSeconds(40).repeaForevver()).build();
    
  • Factory模式
    // quartz获取一个调度器
    Schedulere scheduler = StdSchedulerFactory.getDefaultScheduler();
    // 启动或关闭调度器
    scheduler.start();
    
  • 组件模式
    // 任务组件
    JobDetail job = newJob(MyJob.class).withIdentity("job1","group1").build();
    // 触发器组件
    Trigger trigger = newTrigger().withIdentity("trigger1","group1").startNow()
    .withSchedule(simpleSchedule().withIntervalInSeconds(40).repeaForevver()).build();
    // 调度器组件
    scheduler.scheduleJob(job,trigger);
    
  • 链式编程
    Trigger trigger = newTrigger().withIdentity("trigger1","group1").startNow()
    .withSchedule(simpleSchedule().withIntervalInSeconds(40).repeaForevver()).build();
    

Quartz核心概念

任务Job

Job就是你想要实现的任务类,每一个Job必须实现org.quartz.job接口,且只需要实现接口定义的execute()方法

触发器Trigger

Trigger为你执行任务的触发器,比如你想要每天定时3点钟发送一份统计邮件,Trigger将会设置3点进行执行该任务
Trigger主要包含两种SimpleTrigger和CronTrigger两种

调度器Scheduler

Scheduler为任务的调度器,它会将任务job及触发器Trigger整合起来,负责基于Trigger设定的时间来执行job

Quartz体系结构

Quartz体系结构

Quartz常用API

以下是Quartz编程API几个重要接口,也是Quartz的重要组件

  • Scheduler 用于与调度程序交互的主要程序接口。
    Scheduler调度程序-任务执行计划表,,只有安排进执行计划的任务Job(通过scheduler.scheduleJon方法安排执行计划),当它预先定义的执行条件到了的时候(任务触发trigger),该任务才会执行。
  • Job 我们预先定义的希望在未来时间能被调度程序执行的任务类,我们可以自定义。
  • JobDetail 使用JobDetail来定义定时任务的实例,JobDetail实例是通过JobBuilder类创建的。
    可以理解为JobDetail就是前面Job的一个实例
  • JobDataMap 可以包含不限量的(序列化的)数据对象,在Job实例执行的时候,可以使用其中的数据;
    JobDataMap是Java Map接口的一个实现,额外增加了一些便于存取基本数据类型的数据的方法。
  • Trigger 触发器,Trigger对象是用来触发执行Job的。
    当调度一个Job时,我们实例一个触发器然后调整它的属性来满足Job执行的条件。
    表明任务在什么时候会执行。定义了一个已经被安排的任务将会在什么时候执行的时间条件,比如每2秒就执行一次
  • JobBuilder 用于声明一个任务示例,也可以定义关于该任务的详情比如任务名、组名等,这个声明的实例将会作为一个实际执行的任务。
    实际就是通过JobBuilder创建Job的实例,也就是JobDetail。
  • TriggerBuilder 触发器创建器,用于创建触发器trigger实例。
  • JobListener、TriggerListener、SchedulerListener 监听器,用于对组件的监听。

Quartz基本使用

准备工作

创建Maven工程
引入依赖
<!-- quartz核心包 -->
<dependency>
    <groupId>org.quartz-scheduler</groupId>
    <artifactId>quartz</artifactId>
    <version>2.3.2</version>
</dependency>
<!-- quartz工具包 -->
<dependency>
    <groupId>org.quartz-scheduler</groupId>
    <artifactId>quartz-jobs</artifactId>
    <version>2.3.2</version>
</dependency>
<!-- slf4j-log4j整合包 -->
<dependency>
    <groupId>org.slf4j</groupId>
    <artifactId>slf4j-log4j12</artifactId>
    <version>1.7.12</version>
    <scope>test</scope>
</dependency>
<!-- log4j日志包 -->
<dependency>
    <groupId>log4j</groupId>
    <artifactId>log4j</artifactId>
    <version>1.2.17</version>
</dependency>
指定项目编译环境
<plugin>
	<gropuId>org.apache.maven.plugins</groupId>
	<artifactId>maven-compiler-plugin</artifactId>
	<version>3.5.1</version>
	<configuration>
		<target>1.8</target>
		<source>1.8</source>
	</configuration>
</plugin>
引入log4j配置文件(log4j.properties)
### log日志输出到控制台 ###
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.Target=System.out
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%d{ABSOLUTE} %5p %c{1}:%L - %m%n

### log日志输出到文件 ###
log4j.appender.file=org.apache.log4j.FileAppender
log4j.appender.file.File=c:/mylog.log
log4j.appender.file.layout=org.apache.log4j.PatternLayout
log4j.appender.file.layout.ConversionPattern=%d{ABSOLUTE} %5p %c{1}:%L -%m%n

### 设置log4j级别(默认为debug级别,修改为info级别)以及使用上面那种方式,下面是输出到控制台 ###
log4j.rootLogger=info,stdout

入门案例

定义一个任务类(实现Job接口)

任务类就是定义我们具体需要执行的任务
此处我们定义就是打印当前时间

public class HelloJob implements Job {
    @Override
    public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException {
        System.out.println("任务类:具体需要执行的任务");
        System.out.println("当前时间为:"+new SimpleDateFormat("yyyy年MM月dd日 HH:mm:ss").format(new Date()));
    }
}
创建任务调度类(Demo)
实现步骤
  • 从工厂中获取一个调度器备用
  • 通过JobBuilder创建一个任务实例JobDetail
    绑定自定义任务类,也就是实现了Job接口的类
    设置名称以及分组名称,然后构建实例
  • 通过TriggerBuilder创建一个触发器实例Trigger
    设置触发器名称以及分组名称
    设置触发器启动时间,可以给定时间,也可以立即启动
    设置具体的触发器类型,且设置触发条件,然后进行构建
  • 通过前面的调度器关联任务实例和触发器
  • 启动调度器,也可以停止shutDown,或者暂停
示例代码
public class Demo {
    public static void main(String[] args) throws SchedulerException {
        // 1.调度器(Scheduler)从工厂中获取一个任务调度的实例
        // 此处获取默认的调度器(默认:实例化new StdSchedulerFactory()后获取)
        Scheduler scheduler = StdSchedulerFactory.getDefaultScheduler();
        // 2. 任务实例(JobDetail)
        // 加载任务类,与HelloJob完成绑定,要求HelloJob实现Job接口
        JobDetail jobDetail = JobBuilder.newJob(HelloJob.class)
                // 参数1(自定义):任务的名称(唯一实例) 参数2(自定义):任务组的名称,可以将任务分组执行
                .withIdentity("job1", "group1")
                .build();
        // 3. 触发器(Trigger)
        // 加载触发器
        Trigger trigger = TriggerBuilder.newTrigger()
                // 参数1(自定义):触发器名称(唯一实例)
                // 参数2(自定义):触发器组名称,触发器也可分组
                .withIdentity("trigger1", "group1")
                // 设置触发器启动,可以指定时间,也可以马上启动,下面就是马上启动
                .startNow()
                // 触发器两种任选一种,选择执行方式为重复执行,按照秒重复,时间为5秒
                // 该方法为静态方法,直接通过类调用,如果是普通方法,创建实例SimpleScheduleBuilder.simpleSchedule()
                .withSchedule(SimpleScheduleBuilder.repeatSecondlyForever(5))
                .build();
        // 4. 通过调度器关联任务和触发器,保证任务按照触发器定义的条件执行
        scheduler.scheduleJob(jobDetail,trigger);
        // 5. 启动调度器
        scheduler.start();
    }
}
实现效果

在这里插入图片描述

Job和JobDetail介绍

  • Job:工作任务调度的接口,任务类需要实现该接口。该接口中定义execute方法类似JDK提供的TimeTask类的run方法。在里面编写任务执行的业务逻辑。
  • Job实例在Quartz中的生命周期:每次调度器执行job时,它在调用execute方法前会创建一个新的job实例(通过构造方法得知,每次执行execute方法前会创建job实例),当调用完execute方法后,关联的Job对象实例会被释放,释放的实例会被垃圾回收机制回收。
  • JobDetail:JobDetail为Job实例提供了许多设置属性,以及jobDetaMap成员变量属性,它用来存储特定的job实例的状态信息调度器需要借助JobDetail对象来添加Job实例。
  • JobDetail重要属性:name、group、jobClass、jobDataMap
    JobDetail jobDetail = JobBuilder.newJob(HelloJob.class)
                // 参数1(自定义):任务的名称(唯一实例) 参数2(自定义):任务组的名称,可以将任务分组执行
                .withIdentity("job1", "group1")
                .build();
        System.out.println("name:"+jobDetail.getKey().getName());
        System.out.println("group:"+jobDetail.getKey().getGroup());
        System.out.println("jobClass:"+jobDetail.getJobClass().getName());
        // 如果没有设置组名,会有默认的组名,为DEFAULT
        JobDetail jobDetail = JobBuilder.newJob(HelloJob.class)
                // 参数1(自定义):任务的名称(唯一实例) 参数2(自定义):任务组的名称,可以将任务分组执行
                .withIdentity("job1")
                .build();
         System.out.println("group:"+jobDetail.getKey().getGroup());// DEFAULT
    

JobExecutionContext介绍

  • 当Scheduler调用一个job,会将jobExecutionContext传递给job的execute()方法
    public class HelloJob implements Job {
    	@Override
    	public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException {
        	System.out.println("任务类:具体需要执行的任务");
        	System.out.println("当前时间为:"+new SimpleDateFormat("yyyy年MM月dd日 HH:mm:ss").format(new Date()));
    	}
    }
    
  • job能通过JobExecutionContext对象访问到Quartz运行时环境以及job本身的明细数据(明细数据通过JobDataMap传递获取,详细看下面Map使用)
    public class HelloJob implements Job {
    	@Override
    	public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException {
        	/*
         	* 获取JobDetail的内容,通过JobExecutionContext
         	*/
        	JobDetail jobDetail = jobExecutionContext.getJobDetail();
        	JobKey key = jobDetail.getKey();
        	System.out.println("工作任务名称:"+key.getName());
        	System.out.println("工作任务的组:"+key.getGroup());
        	System.out.println("任务类的名称(路径)"+jobDetail.getJobClass().getName());
        	System.out.println("任务类的名称:"+jobDetail.getJobClass().getSimpleName());
    
        	System.out.println("任务类:具体需要执行的任务");
        	System.out.println("当前时间为:"+new SimpleDateFormat("yyyy年MM月dd日 HH:mm:ss").format(new Date()));
    	}
    }
    

JobDataMap介绍

使用Map获取
  • 在进行任务调度时,JobDataMap存储在JObExecutionContext中,非常方便获取。
  • JobDataMap可以用来装载任何可序列化的数据对象,,当Job实例对象被执行时这些参数对象会传递给它。
  • JobDataMap实现了JDK的Map接口,并且添加了非常方便的方法用来存取基本数据类型。
初始化触发器及JobDetail时存入值
  • 存入数据时,JobDetail中的键值对与Trigger中的键值对可以重复,不会被覆盖
public class Demo {
    public static void main(String[] args) throws SchedulerException {
        Scheduler scheduler = StdSchedulerFactory.getDefaultScheduler();
        JobDetail jobDetail = JobBuilder.newJob(HelloJob.class)
                .withIdentity("job1", "group1")
                // 构建JobDetail时在JobDataMap中存入键值对
                .usingJobData("我是键","我是值")
                .build();
        Trigger trigger = TriggerBuilder.newTrigger()
                .withIdentity("trigger1", "group1")
                .startNow()
                .withSchedule(SimpleScheduleBuilder.repeatSecondlyForever(5))
                // 构建触发器时在 JobDataMap中存入键值对
                .usingJobData("我是trigger键","我是trigger值")
                .build();
        scheduler.scheduleJob(jobDetail,trigger);
        scheduler.start();
    }
任务实现类中取值
  • 获取值时,因为JobDetail和Trigger都存入的值,所以要分别获取
public class HelloJob implements Job {
    @Override
    public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException {
        /*
         * 获取JobDetail的内容,通过JobExecutionContext
         */
        JobDetail jobDetail = jobExecutionContext.getJobDetail();
        // 通过JobDetail获取其中的JobDataMap,然后获取其中的键值对
        JobDataMap jobDataMap = jobDetail.getJobDataMap();
        String string = jobDataMap.getString("我是键");
        System.out.println(string);

        /*
         * 获取Trigger的内容,通过JobExecutionContext
         */
        Trigger trigger = jobExecutionContext.getTrigger();
        // 通过Trigger获取其中的JobDataMap,然后获取键值对
        JobDataMap triggerJobDataMap = trigger.getJobDataMap();
        String string1 = triggerJobDataMap.getString("我是trigger键");
        System.out.println(string1);

        System.out.println("任务类:具体需要执行的任务");
        System.out.println("当前时间为:"+new SimpleDateFormat("yyyy年MM月dd日 HH:mm:ss").format(new Date()));
    }
}
setter方法取值
  • Job实现类中添加setter方法,对应JobDataMap中的键名
  • Quartz框架默认的JobFactory实现类在初始化Job实例对象时会自动调用这些setter方法。
setter方法直接赋值取值
public class HelloJob implements Job {

    // 我们在JobDetail或Trigger创建时,在JobDataMap存入了键值对
    // 此处我们可以通过定义同键名的setter方法,系统会自动进行赋值操作
    private String 我是键;

    public void set我是键(String 我是键) {
        this.我是键 = 我是键;
    }

    @Override
    public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException {
        // setter会直接进行赋值,此处我们直接打印即可
        System.out.println(我是键);
        System.out.println("任务类:具体需要执行的任务");
        System.out.println("当前时间为:"+new SimpleDateFormat("yyyy年MM月dd日 HH:mm:ss").format(new Date()));
    }
}
注意点
  • 如果在JobDetail和Trigger中存入了同名的Key
  • 这种情况下,我们通过第一种方式取值没有问题
  • 但是通过setter方法取值时,因为无法指定从Trigger取值或从JobDetail取值
  • 所以,遇到键同名的情况,setter的方式会将trigger中的值覆盖JobDetail中的值
JobExecutionContext获取其他值
public class HelloJob implements Job {
    @Override
    public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException {
        // 获取JobDetail
        JobDetail jobDetail = jobExecutionContext.getJobDetail();
        System.out.println("任务的唯一名称:"+jobDetail.getKey().getName());
        System.out.println("任务的组的名称:"+jobDetail.getKey().getGroup());
        // 获取Trigger
        Trigger trigger = jobExecutionContext.getTrigger();
        System.out.println("trigger唯一名称:"+trigger.getKey().getName());
        System.out.println("trigger组的名称:"+trigger.getKey().getGroup());
        // 获取其他值
        System.out.println("获取当前任务的执行时间" + jobExecutionContext.getFireTime());
        System.out.println("获取下次任务的执行时间" + jobExecutionContext.getNextFireTime());


        System.out.println("任务类:具体需要执行的任务");
        System.out.println("当前时间为:"+new SimpleDateFormat("yyyy年MM月dd日 HH:mm:ss").format(new Date()));
    }
}

有状态的Job和无状态的Job

@PersistJobDataAfterExecution注解的使用

  • 有状态的Job可以理解为多次Job调用期间可以持有一些状态信息,这些状态信息存储在JobDataMap中,也可以认为就是多个job会共享JobDataMap中的数据,这多次任务之间会有联动。
  • 而默认的无状态job每次调用时会创建一个新的JobDataMap。也就是每次新的任务都睡初始化所有数据
无状态演示(无注解)
在JobDetail中存入一个count键值对
public class Demo {
    public static void main(String[] args) throws SchedulerException {
        Scheduler scheduler = StdSchedulerFactory.getDefaultScheduler();
        JobDetail jobDetail = JobBuilder.newJob(HelloJob.class)
                .withIdentity("job1", "group1")
                // 构建JobDetail时在JobDataMap中存入键值对
                .usingJobData("count",0)
                .build();
        Trigger trigger = TriggerBuilder.newTrigger()
                .withIdentity("trigger1", "group1")
                .startNow()
                .withSchedule(SimpleScheduleBuilder.repeatSecondlyForever(5))
                .build();
        scheduler.scheduleJob(jobDetail,trigger);
        scheduler.start();
    }
}
在job中取出且自增,重新存入,是在count的自增
public class HelloJob implements Job {
    // 通过setter取出count值
    private Integer count;

    public void setCount(Integer count) {
        this.count = count;
    }

    @Override
    public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException {
        // count自增
        ++count;
        System.out.println("count的值为:"+count);
        // 重新存入到JobDataMap中
        jobExecutionContext.getJobDetail().getJobDataMap().put("count",count);
        
        System.out.println("任务类:具体需要执行的任务");
        System.out.println("当前时间为:"+new SimpleDateFormat("yyyy年MM月dd日 HH:mm:ss").format(new Date()));
    }
}
查看结果,多次任务都会重新初始化数据,数据没有实现自增

在这里插入图片描述

有状态演示(在job实现类添加注解,其他代码不动)
@PersistJobDataAfterExecution
public class HelloJob implements Job {
    // 通过setter取出count值
    private Integer count;

    public void setCount(Integer count) {
        this.count = count;
    }

    @Override
    public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException {
        // count自增
        ++count;
        System.out.println("count的值为:"+count);
        // 重新存入到JobDataMap中
        jobExecutionContext.getJobDetail().getJobDataMap().put("count",count);

        System.out.println("任务类:具体需要执行的任务");
        System.out.println("当前时间为:"+new SimpleDateFormat("yyyy年MM月dd日 HH:mm:ss").format(new Date()));
    }
}
查看结果,多次任务都会共享数据,实现自增

在这里插入图片描述

结论

Job实现类中没有添加@PersistJobDataAfterExecution注解,每次调用时都会创建一个新的的JobDataMap,不会累加
Job实现类中添加@PersistJobDataAfterExecution注解,每次Job调用期间可以持有一些状态信息,即可以实现count的累加。

Trigger介绍

在这里插入图片描述

Quartz有一些不同的触发器类型,不过,用得最多的是SimpleTrigger和CronTrigger

  • jobKey:表示job实例的标识,触发器被触发时,该指定的job实例会 被执行
  • startTime:表示触发器的时间表,第一次开始被触发的时间,它的数据类型是java.util.Date
  • endTime:指定触发器终止被触发的时间,它的数据类型是java.util.Date

触发器案例

任务类(获取上面三个参数)
@PersistJobDataAfterExecution
public class HelloTriggerJob implements Job {
    @Override
    public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException {
        SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        System.out.println("我是任务内容,当前时间为" + format.format(new Date()));
        // 获取jobKey、startTime和endTime三个参数
        Trigger trigger = jobExecutionContext.getTrigger();
        System.out.println("jobKey为:" + trigger.getJobKey());
        System.out.println("jobName为:" + trigger.getJobKey().getName());
        System.out.println("jobGroup为:" + trigger.getJobKey().getGroup());
        System.out.println("任务的开始时间:" + format.format(trigger.getStartTime()));
        System.out.println("任务的结束时间:" + format.format(trigger.getEndTime()));
    }
}
执行类(设置上面三个参数)
public class HelloTriggerDemo {
    public static void main(String[] args) throws SchedulerException {
        // 1. 创建调度器
        Scheduler scheduler = StdSchedulerFactory.getDefaultScheduler();
        // 设置任务开始时间变量,当前时间3秒后开始执行
        Date startTime = new Date();
        startTime.setTime(startTime.getTime()+3000);
        // 设置任务结束时间变量,当前时间10秒后结束整个任务
        Date endTime = new Date();
        endTime.setTime(endTime.getTime()+10000);
        // 2. 创建任务实例
        JobDetail jobDetail = JobBuilder.newJob(HelloTriggerJob.class)
                .withIdentity("job1", "group1")
                .build();
        // 3. 创建触发器
        Trigger trigger = TriggerBuilder.newTrigger()
                .withIdentity("trigger1", "group1")
                // 设置触发器,没3秒执行一次任务
                .withSchedule(SimpleScheduleBuilder.repeatSecondlyForever(3))
                // 设置任务开始时间
                .startAt(startTime)
                // 设置任务结束时间
                .endAt(endTime)
                .build();
        // 4. 调度器绑定任务和触发器
        scheduler.scheduleJob(jobDetail,trigger);
        // 5. 启动调度器
        scheduler.start();
    }
}
结果分析
  • 任务在设定的时间才开始执行,不会跟之前一样立即执行
  • 任务在结束时间之后不再执行,虽然设置了每3秒执行一次,到了结束时间后不再执行
  • 虽然任务不再执行,但是整个程序不会停止运行

SimpleTrigger触发器

SimpleTrigger对于设置和使用是最为简单的一种QuartzTrigger
它是为那种需要在特定的日期/时间启动,且以一个可能的间隔时间重复执行n次的Job所设计的

案例展示
案例一:在一个指定的时间段内,执行一次作业任务
public class SimpleTriggerDemo {
    public static void main(String[] args) throws SchedulerException {
        // 创建调度器
        Scheduler scheduler = StdSchedulerFactory.getDefaultScheduler();
        // 创建任务实例
        JobDetail jobDetail = JobBuilder.newJob(SimpleTriggerJob.class)
                .withIdentity("name", "group")
                .build();
        // 创建触发器,立即执行,执行一次结束
        Trigger trigger = TriggerBuilder.newTrigger()
                .withIdentity("trigger", "group")
                .startNow()
                .build();
        // 绑定
        scheduler.scheduleJob(jobDetail,trigger);
        // 启动
        scheduler.start();
    }
}
案例二:在指定的时间间隔内多次执行作业任务
  • 设置时间间隔,不限次数
    public class SimpleTriggerDemo {
    	public static void main(String[] args) throws SchedulerException {
        	// 创建调度器
        	Scheduler scheduler = StdSchedulerFactory.getDefaultScheduler();
        	// 创建任务实例
        	JobDetail jobDetail = JobBuilder.newJob(SimpleTriggerJob.class)
                .withIdentity("name", "group")
                .build();
        	// 创建触发器
        	Trigger trigger = TriggerBuilder.newTrigger()
                .withIdentity("trigger", "group")
                .startNow()
                // 触发器每3秒执行一次,不限次数
                .withSchedule(SimpleScheduleBuilder.simpleSchedule().repeatSecondlyForever(3))
                .build();
        	// 绑定
        	scheduler.scheduleJob(jobDetail,trigger);
        	// 启动
        	scheduler.start();
    	}
    }
    
  • 设置时间间隔,限制次数(次数默认值是0,2代表执行三次)
    public class SimpleTriggerDemo {
    	public static void main(String[] args) throws SchedulerException {
        	// 创建调度器
        	Scheduler scheduler = StdSchedulerFactory.getDefaultScheduler();
        	// 创建任务实例
        	JobDetail jobDetail = JobBuilder.newJob(SimpleTriggerJob.class)
                .withIdentity("name", "group")
                .build();
        	// 创建触发器
        	Trigger trigger = TriggerBuilder.newTrigger()
                .withIdentity("trigger", "group")
                .startNow()
                .withSchedule(SimpleScheduleBuilder.simpleSchedule()
                        // 触发器每3秒执行一次,执行3次结束
                        .repeatSecondlyForever(3).withRepeatCount(2))
                .build();
        	// 绑定
        	scheduler.scheduleJob(jobDetail,trigger);
        	// 启动
        	scheduler.start();
    	}
    }
    
案例三:指定任务的结束时间
public class SimpleTriggerDemo {
    public static void main(String[] args) throws SchedulerException {
        // 创建调度器
        Scheduler scheduler = StdSchedulerFactory.getDefaultScheduler();
        // 创建任务实例
        JobDetail jobDetail = JobBuilder.newJob(SimpleTriggerJob.class)
                .withIdentity("name", "group")
                .build();
        // 设置任务结束时间变量,当前时间10秒后结束整个任务
        Date endTime = new Date();
        endTime.setTime(endTime.getTime()+10000);
        // 创建触发器
        Trigger trigger = TriggerBuilder.newTrigger()
                .withIdentity("trigger", "group")
                .startNow()
                // 设置结束时间,优先次数,也就是到了结束时间就结束,无论执行次数
                // 有没有达到设置的值
                .endAt(endTime)
                .withSchedule(SimpleScheduleBuilder.simpleSchedule()
                        // 触发器每3秒执行一次,执行3次结束
                        .repeatSecondlyForever(3).withRepeatCount(2))
                .build();
        // 绑定
        scheduler.scheduleJob(jobDetail,trigger);
        // 启动
        scheduler.start();
    }
}
注意点
  • SimpleTrigger的属性有:开始时间、结束时间、重复次数和重复的时间间隔
  • 重复次数属性的值可以为0、正整数、或常量SimpleTrigger.REPEAT_INDEFINITELY。
  • 重复的时间间隔属性必须为大于0或长整形的正整数,以毫秒作为时间单位,当重复的时间间隔为0时,意味着与Trigger同时触发执行,但是会报错
  • 如果指定结束时间属性值,则结束时间属性优先于重复次数属性,这样的好处在于:当我们需要创建一个每隔10秒触发一次直到指定的结束时间的Trigger,而无需去计算从开始到结束的所有重复次数,我们只需要简单的指定结束时间和使用REPEAT_INDEFINITELY作为重复次数的属性值即可

CronTrigger触发器

概念

如果你需要想日历那样按日程来触发任务,而不是想SimpleTrigger那样每隔特定的间隔时间触发,CronTrigger通常比SimpleTrigger更有用,因为它是基于日历的作业调度器。
使用CronTrigger,你可以指定诸如“每个周五中午”,或者“每个工作日的9:30”或者“从每个周一、周三、周五的上午9:00到上午10:00之间每隔五分钟”这样日程安排来触发。
甚至,像SimpleTrigger一样,CronTrigger也有一个startTime以指定日程从什么时候开始,也有一个(可选的)endTime以指定何时日程不再继续。

Cron Expressions–Cron表达式
概念

Cron表达式被用来配置CronTrigger实例。Cron表达式是一个由7个子表达式组成的字符串。每个子表达式都描述了一个单独的日程细节。这些子表达式用空格分隔,分别表示:

表示
  • Seconds 秒
  • Minutes 分钟
  • Hours 小时
  • Day-of-Month 月中的天
  • Month 月
  • Day-of-Week 周中的天
  • Year(optional field)年(可选的)
取值
字段是否必填允许值运行的特殊字符
0-59,- * /
0-59, - * /
0-23, - * /
1-31, - * / ? L W C
1-12或者JAN-DEC, - * /
1-7或者SUN-SAT, - * / ? L C #
不填写,或者1970-2099, - * /

单个子表达式可以包含范围或者列表。
例如:前面例子中的周中的天这个域的合法值为0到59,小时的合法范围是0到23,Day-of-Month中值的合法范围是1到31,但是需要注意不同的月份中的天数不同
月份的合法值是1到12.或者用字符串JAN,FEB MAR,APR,MAY,JUN,JUL,AUG,SEP,OCT,NOV及DEC来表示
Days-of-Week可以用1到7来表示(1=星期日)或者用字符串SUN,MON,TUE,THU,FRI和SAT来表示

特殊符号含义
*用来表示域中的“每个”可能的值。因此在“Month”域中的*表示每个月,而在Day-of-Week域中的*则表示“周中的每一天”
?表示不指定值,使用的场景为不需要关系当前设置这个字段的值。因为“月份中国的日期”和星期中的日期这两个元素是互斥的,因此应该通过设置一个问号(?)来表明你不想设置的那个字段
-表示区间,例如在小时上设置10到12,表示10,11,12点都会触发
,表示指定多个值,例如在周字段上设置“MON,WED,FRI”,表示周一、周三、周五触发
/表示值的增量,例如,如果分钟域中放入‘0/15’,它表示“每隔15分钟,从0开始”,如果在分钟域中使用‘3/20’,则表示“小时中每隔20分钟,从第3分钟开始”,或者另外相同的形式就是‘3,23,43’
L可以在day-of-month及day-of-week中使用,这个字符是“last”的简写,但是在两个域中的意义不同。例如,在day-of-month域中的“L”表示这个月的最后一天,即,一月的31日,非闰年的二月的28日。如果用在day-of-week中,则表示“7”或者“SAT”,但是如果在day-of-week域中,这个字符跟在别的值后面,则表示“当月的最后周XXX”,例如:“6L”或者“FRIL”都表示本月的最后一个周五。当使用‘L’选项时,最重要的是不要指定列表或者值范围,否则会导致混乱
W用来指定距离给定日最接近的周几(在day-of-week域中指定),例如:如果你为day-of-month域指定为“15W”,则表示“距离月中15号最近的周几”
#表示月中的第几个周几。例如:day-of-week域中的“6#3”或者“FRI#3”表示“月中第三个周五”
表达式生成器

有很多的cron表达式在线生成器,下面两个常用仅做参考:
在线Cron表达式生成器
或者
http://www.pdtools.net/tools/becron.jsp

练习
*/5 * * * * ? 每隔5秒执行一次
 0 */1 * * * ? 每隔1分钟执行一次
 0 0 5-15 * * ? 每天5-15点整点触发
 0 0/3 * * * ? 每三分钟触发一次
 0 0-5 14 * * ? 在每天下午2点到下午2:05期间的每1分钟触发 
 0 0/5 14 * * ? 在每天下午2点到下午2:55期间的每5分钟触发
 0 0/5 14,18 * * ? 在每天下午2点到2:55期间和下午6点到6:55期间的每5分钟触发
 0 0/30 9-17 * * ? 朝九晚五工作时间内每半小时
 0 0 10,14,16 * * ? 每天上午10点,下午2点,4点 
 0 0 12 ? * WED 表示每个星期三中午12点
 0 0 17 ? * TUES,THUR,SAT 每周二、四、六下午五点
 0 10,44 14 ? 3 WED 每年三月的星期三的下午2:10和2:44触发 
 0 15 10 ? * MON-FRI 周一至周五的上午10:15触发
 0 0 23 L * ? 每月最后一天23点执行一次
 0 15 10 L * ? 每月最后一日的上午10:15触发 
"15,30,45 * * * * ?" 每15秒,30秒,45秒时触发任务
"15-45 * * * * ?" 15到45秒内,每秒都触发任务
"0 15 10 LW * ?" 每个月最后一个工作日的10点15分0秒触发任务
"0 15 10 ? * 5L" 每个月最后一个星期四的10点15分0秒触发任务
"0 15 10 ? * 5#3" 每个月第三周的星期四的10点15分0秒触发任务
案例
  • 定义任务HelloJobCronTrigger.java
    public class HelloJobCronTrigger implements Job {
    	@Override
    	public void execute(JobExecutionContext context) throws JobExecutionException {
    		// 定义时间
    		Date date = new Date();
    		SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
    		String dateString = dateFormat.format(date);
    		// 定义工作任务内容
    		System.out.println("进行数据库备份操作。当前 任务执行的时间:"+dateString);
    	}
    }
    
  • 触发器执行HelloSchedulerDemoCronTrigger.java
    public class HelloSchedulerDemoCronTrigger {
    	public static void main(String[] args) throws Exception {
    		// 1:从工厂中获取任务调度实例
    		Scheduler scheduler = StdSchedulerFactory.getDefaultScheduler();
    		// 2:定义一个任务调度实例,将该实例与HelloJob绑定,任务类需要实现Job接口
    		JobDetail job = JobBuilder.newJob(HelloJobCroTrigger.class)
    		.withIdentity("job1","group1") //定义实例唯一标识
    		.build();
    		// 3:定义触发器,马上执行,然后每5秒重复执行一次
    		Trigger trigger = TriggerBuilder.newTrigger()
    		.withIdentity("trigger1","group1") //定义该实例唯一标识
    		.whthSchedule(CronScheduleBuilder.cronnSchedule("0/5 * * 6 6 ?")) // 定义表达式
    		.build();
    		// 4: 使用触发器调度任务的执行
    		scheduler.scheduleJob(job,trigger);
    		// 5:开启
    		scheduler.start();
    		//6:关闭
    		shceduler.shutdown();
    	}
    }
    
  • 小提示

    “L”和“W”可以一起使用。(企业可用在工资计算,如每个月的几号发工资)
    ‘#’可表示月中第几周。(可用在计算母亲节、父亲节等)
    周字段英文字母不区分大小写,如MON==mon
    利用工具在线生成

配置、资源SchedulerFactory

概念
  • Quartz以模块方式构架,因此,要使它运行,几个组件必须很好的咬合在一起。幸运的是,已经有了一些现存的助手可以完成这些工作。
  • 所有的Scheduler实例都是有SchedulereFactory创建
  • Quartz的三个核心概念:调度器、任务、触发器,三者之间的关系是:
    在这里插入图片描述
  • 一个作业,比较重要的三要素就是Scheduler、JobDetail、Trigger;而Trigger对于job而言就好比一个驱动器;没有触发器来定时驱动作业,作业就无法运行,对于job而言,一个job可以对应多个Trigger,但对于Trigger而言,一个Trigger只能对应一个job;所有一个Trigger只能被指定一个job,如果你需要一个复杂的触发器计划,你可以创建多个Trigger并指派给它们同一个job任务
调度器Scheduler创建方式

Quartz默认的SchedulerFactory

方式一:StdSchedulerFactory
  • 使用一组参数(java.util.Properties)来创建和初始化Quartz调度器
  • 配置参数一般存储在quartz.properties文件中
  • 调用getScheduler方法就能创建和初始化调度器对象
    SchedulerFactory shcedulerFactory = new SchedulerFactory();
    Scheduler scheduler = shcedulerFactory.getScheduler();
    // 或者是
    Shceduler scheduler = StdSchedulerFactory.getDefaultScheduler();
    // 或者是
    StdSchedulerFactory schedulerFactory = new StdSchedulerFactory();
    Scheduler scheduler = shcedulerFactory.getScheduler();
    
方式二:DirectSchedulerFactory(了解)

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

DirectSchedulerFactory directSchedulerFactory = DirectSchedulerFactory.getInstance();
Scheduler shceduler = directSchedulerFactory.getScheduler();
Scheduler使用方式
方法一:输出调度器开始时间

调度器绑定任务和触发器时返回值

Date date = shceduler.shceduleJob(jobDetail,trigger);
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
System.out.println("调度器开始时间是:"+dateFormat.format(date));
方法二:启动任务调度

void start();

// 启动调度器,通过触发器执行任务
scheduler.start();
方法三:任务调度挂起(暂停)

void standby();
去停止不同,挂起后可以重新启动

// 启动调度器,通过触发器执行任务
scheduler.start();
// 任务执行两秒
Thread.sleep(2000L);
// Scheduler执行两秒后挂起
scheduler.standby();
// 挂起五秒中时间
Thread.sleep(5000L);
// 挂起调度器五秒后再次启动
scheduler.start();
方法四:关闭任务调度

void shutdown();// 该方法可以无参,还可以携带一个Boolean类型参数
shutdown(true):表示会等待所有正在执行的job任务执行完毕后,再进行关闭Scheduler
shutdown(false):即便任务执行了一半,也会直接关闭scheduler

Quartz.properties

概念

前面我们说到调度器创建,使用的属性便是该文件中指定的属性及值
默认路径:在quartz包中的org.quartz中的quartz.properties
创建调度器时会自动读取加载该文件,可以在SchedulerFactory源码中看到
我们也可以项目资源下添加quartz.properties文件,覆盖底层默认的配置文件,名称固定,会自动覆盖

组成部分
调度器属性
  • org.quartz.scheduler.instanceName属性用来区分特定的调度器实例,可以按照功能用途来给调度器取名
  • org.quartz.scheduler.instanceId属性和前者一样,也允许任何字符串,但这个值必须在所有调度器实例中是唯一的,尤其是在一个集群环境中,作为集群的唯一key。假如你想Quartz帮你生成这个值的话,可以设置为AUTO,会自动分配唯一的id值
线程池属性
  • threadCount属性指处理Job的线程个数,至少为1,但最多的话最好不要超过100,在多数机器上设置该值超过100的话会显示得相当不实用了,特别是你的Job执行时间比较长的情况下
  • threadPriority属性指线程的优先级,优先级特别高的线程比级别低的线程优先得到执行。最小为1,最大为10,默认为5
  • org.quartz.threadPool.class一个实现了org.quartz.spi.ThreadPool接口的类,Quartz自带的线程池实现类是org.quartz.smpl.SimpleThreadPool
作业存储设置

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

插件配置

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

也可以通过代码操作一些属性

该方式属于硬编码的方式,如果需要修改属性,可能会修改代码,故而不推荐使用,了解即可

public class QuartzProperties {
	public static void main(String[] args) {
		// 创建工厂实例
		StdScheulerFactory factory = new StdSchedulerFactory();
		// 创建配置工厂的属性对象
		Properties props = new Properties();
		// 添加属性,名称及值的方式
		props.put("org.quartz.threadPool.threadCount","5");
		// 属性名称还可以通过类获取
		props.put(StdSchedulerFactory.PROP_THREAD_POOL_CLASS,"org.quartz.simpl.SimpleThreadPool");
		// 使用定义的属性初始化工厂
		factory.initialize(props);
		Scheduler scheduler = factory.getScheduler();
		// 启动测试
		scheduler.start();
	}
}

Quartz监听器

概念

  • Quartz的监听器用于当任务调度中你所关注事件发生时,能够及时获取这一事件的通知。类似于任务执行过程中的邮件、短信类的提醒。
  • Quartz监听器主要有JobListener、TriggerListener和SchedulerListener三种,顾名思义,分别表示任务、触发器和调度器对应的监听器。三者的使用方法类似,在开始介绍三种监听器之前,需要明确两个概念:全局监听器与非全局监听器,二者的区别在于:

    全局监听器能够接收到所有的Job/Trigger的事件通知
    非全局监听器只能接收到在其上注册的Job或Trigger的事件,不在其上注册的Job或Trigger则不会进行监听

JobListener

概念

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

public interface JobListener {
	// 用于获取该JobListener的名称
    String getName();
	// Scheduler在JobDetail将要被执行时调用这个方法
    void jobToBeExecuted(JobExecutionContext var1);
	// Scheduler在JobDetail即将被执行,但又被TriggerListener否决时会调用该方法
    void jobExecutionVetoed(JobExecutionContext var1);
	// Scheduler在JobDetail被执行之后调用这个方法
    void jobWasExecuted(JobExecutionContext var1, JobExecutionException var2);
}
示例
创建工作类JobListenerJob
public class JobListenerJob implements Job {
    @Override
    public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException {
        // 获取到系统当前的时间
        SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        String date = dateFormat.format(new Date());
        // 工作内容,打印获取到的时间
        System.out.println("工作内容,打印当前时间为:" + date);
    }
}
创建自定义Job监听器MyJobListener
public class MyJobListener implements JobListener {
    @Override
    public String getName() {
        // 获取监听器名称,直接返回该监听器对象的类名称,用于测试
        return this.getClass().getSimpleName();
    }

    @Override
    public void jobToBeExecuted(JobExecutionContext jobExecutionContext) {
        // 任务被执行前调用该对象
        System.out.println("任务将要被执行");
        // 此处可以通过给定参数获取任务信息,如任务名称
        String name = jobExecutionContext.getJobDetail().getKey().getName();
        System.out.println("任务名称为 " + name);
        try {
            // 任务一秒后执行
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    @Override
    public void jobExecutionVetoed(JobExecutionContext jobExecutionContext) {
        // 任务将要被执行但被触发器监听器否决时调用
        System.out.println("任务被触发器监听器否决了呀");
    }

    @Override
    public void jobWasExecuted(JobExecutionContext jobExecutionContext, JobExecutionException e) {
        // 任务执行结束后执行
        System.out.println("任务执行完毕");
    }
}
创建调度器执行任务并注册监听(在调度器调度任务触发器之后)
  * 调度器调度任务与触发器之后,启动调度器之前注册监听器给任务
  * 通过调度器获取到任务监听器管理器
  * 再通过管理器添加任务监听器,直接给自定义的监听器对象即可
  * 添加监听器时两个参数,参数一为给定要注册的监听器
  * 参数二为设置该监听器是全局监听或者局部监听
  • 注册全局任务监听器
    scheduler.getListenerManager()
                .addJobListener(new MyJobListener(), EverythingMatcher.allJobs());
    
  • 注册局部任务监听器
    scheduler.getListenerManager()
                .addJobListener(new MyJobListener(), KeyMatcher.keyEquals(JobKey.jobKey("job1","group1")));
    
public class JobListenerDemo {
    public static void main(String[] args) throws SchedulerException {
        // 创建调度器,通过默认工厂获取
        Scheduler scheduler = StdSchedulerFactory.getDefaultScheduler();
        // 创建任务实例,与JobListener绑定
        JobDetail jobDetail = JobBuilder.newJob(JobListenerJob.class)
                // 设置任务名称及任务分组
                .withIdentity("job1","group1")
                .build();
        // 创建触发器
        Trigger trigger = TriggerBuilder.newTrigger()
                // 设置触发器名称及触发器分组
                .withIdentity("trigger1","group1")
                // 设置触发条件,具体的触发器类型,每两秒触发一次
                .withSchedule(SimpleScheduleBuilder.repeatSecondlyForever(2))
                .build();
        // 调度任务与触发器
        scheduler.scheduleJob(jobDetail,trigger);
        // 创建并注册一个全局任务监听器
        scheduler.getListenerManager()
                .addJobListener(new MyJobListener(), EverythingMatcher.allJobs());
        // 创建并注册一个局部任务监听器
        scheduler.getListenerManager()
                .addJobListener(new MyJobListener(), KeyMatcher.keyEquals(JobKey.jobKey("job1","group1")));
        // 启动调度器
        scheduler.start();
    }
}

TriggerListener

概念

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

public interface TriggerListener {
	// 用于获取触发器的名称
    String getName();
	// 当与监听器相关联的Trigger被触发,Job上的execute()方法将要被执行时,Scheduler就调用该方法
    void triggerFired(Trigger var1, JobExecutionContext var2);
	// 在Trigger触发后,Job将要被执行时由Scheduler调用这个方法。TriggerListener给了一个选择去否决Job的执行,假如这个方法返回true,这个Job将不会为此次Trigger触发而得到执行
    boolean vetoJobExecution(Trigger var1, JobExecutionContext var2);
	// Scheduler调用这个方法是在Trigger错过触发时。你应该关注此方法中持续时间上的逻辑:在出现许多错过触发的Trigger时,长逻辑会导致骨牌效应,你应当保持这上方法尽量的小
    void triggerMisfired(Trigger var1);
	// Trigger被触发并且完成了Job的执行时,Scheduler调用这个方法
    void triggerComplete(Trigger var1, JobExecutionContext var2, CompletedExecutionInstruction var3);
}
示例
创建任务类TriggerListrnerJob
public class TriggerListrnerJob implements Job {
    @Override
    public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException {
        // 获取到系统当前的时间
        SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        String date = dateFormat.format(new Date());
        // 工作内容,打印获取到的时间
        System.out.println("工作内容,打印当前时间为:" + date);
    }
}
创建自定义Trigger监听器类
public class MyTriggerListener implements TriggerListener {
    @Override
    public String getName() {
        // 获取监听器名称
        return this.getClass().getSimpleName();
    }

    @Override
    public void triggerFired(Trigger trigger, JobExecutionContext jobExecutionContext) {
        // 触发器触发,任务执行前被调用
        System.out.println("触发器被触发,将要执行Job任务了");
    }

    @Override
    public boolean vetoJobExecution(Trigger trigger, JobExecutionContext jobExecutionContext) {
        // true表示触发器否决job执行,false则正常执行
        // 该方法在触发后Scheduler正常调用,只是影响Job的执行而已
        return false;
    }

    @Override
    public void triggerMisfired(Trigger trigger) {
        // 触发器未正常触发执行
        System.out.println("触发器没有正常触发,错过触发");
    }

    @Override
    public void triggerComplete(Trigger trigger, JobExecutionContext jobExecutionContext, Trigger.CompletedExecutionInstruction completedExecutionInstruction) {
        // 触发器触发,job执行后调用
        System.out.println("job执行完毕");
    }
}
创建调度器执行任务并注册监听(与任务监听器使用基本类似)
  • 注册全局触发器监听器
    scheduler.getListenerManager()
                .addTriggerListener(new MyTriggerListener (), EverythingMatcher.allTriggers());
    
  • 注册局部触发器监听器
    scheduler.getListenerManager()
                .addTriggerListener(new MyTriggerListener(), KeyMatcher.keyEquals(TriggerKey.triggerKey("trigger1","group1")));
    
public class TriggerListenerDemo {
    public static void main(String[] args) throws SchedulerException {
        // 创建调度器,通过默认工厂获取
        Scheduler scheduler = StdSchedulerFactory.getDefaultScheduler();
        // 创建任务实例,与JobListener绑定
        JobDetail jobDetail = JobBuilder.newJob(JobListenerJob.class)
                // 设置任务名称及任务分组
                .withIdentity("job1","group1")
                .build();
        // 创建触发器
        Trigger trigger = TriggerBuilder.newTrigger()
                // 设置触发器名称及触发器分组
                .withIdentity("trigger1","group1")
                // 设置触发条件,具体的触发器类型,每两秒触发一次
                .withSchedule(SimpleScheduleBuilder.repeatSecondlyForever(2))
                .build();
        // 调度任务与触发器
        scheduler.scheduleJob(jobDetail,trigger);
        // 创建并注册一个全局任务监听器
        scheduler.getListenerManager()
                .addTriggerListener(new MyTriggerListener(),EverythingMatcher.allTriggers());
        // 创建并注册一个局部任务监听器
        scheduler.getListenerManager()
                .addTriggerListener(new MyTriggerListener(), KeyMatcher.keyEquals(TriggerKey.triggerKey("trigger1","group1")));
        // 启动调度器
        scheduler.start();
    }
}

SchedulerListener

概念

SchedulerListener会在Scheduler的生命周期中关键事件发生时被调用。与Scheduler有关的事件包括增加一个Job/trigger、删除一个Job/Trigger、Scheduler发生严重错误和关闭Scheduler等

public interface SchedulerListener {
	// 用于部署JobDetail时调用
    void jobScheduled(Trigger var1);
	// 用于卸载JobDetail时调用
    void jobUnscheduled(TriggerKey var1);
	// 当一个Trigger来到了再也不会触发的状态时调用这个方法。除非这个Job已经设置成了持久性,否则它就会从Scheduler中移除
    void triggerFinalized(Trigger var1);
	// 
    void triggerPaused(TriggerKey var1);
	// Scheduler调用这个方法是发生在一个Trigger或Trigger组被暂停时,假如是Trigger组的话,TriggerName参数将为null
    void triggersPaused(String var1);
	// 
    void triggerResumed(TriggerKey var1);
	// Scheduler调用这个方法是发生成一个Trigger或Trigger组从暂停中恢复时,假如是Trigger组的话,TriggerName参数降为null
    void triggersResumed(String var1);
	// 
    void jobAdded(JobDetail var1);
	// 
    void jobDeleted(JobKey var1);
	// 
    void jobPaused(JobKey var1);
	// 当一个或一组JobDetail暂停时调用这个方法
    void jobsPaused(String var1);
	// 
    void jobResumed(JobKey var1);
	// 当一个或一组job从暂停上恢复时调用这个方法,假如一个job组,jobName参数将为空
    void jobsResumed(String var1);
	// 在Scheduler的正常运行期间产生一个严重错误时调用这个方法
    void schedulerError(String var1, SchedulerException var2);
	// 当Scheduler处于StandBy模式时,调用该方法
    void schedulerInStandbyMode();
	// 当Scheduler开启时,调用该方法
    void schedulerStarted();
	// 
    void schedulerStarting();
	// 当Scheduler停止时,调用该方法
    void schedulerShutdown();
	// 
    void schedulerShuttingdown();
	// 当Scheduler中的数据被清除时,调用该方法
    void schedulingDataCleared();
}
示例
创建任务类SchedulerListrnerJob
public class SchedulerListrnerJob implements Job {
    @Override
    public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException {
        // 获取到系统当前的时间
        SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        String date = dateFormat.format(new Date());
        // 工作内容,打印获取到的时间
        System.out.println("工作内容,打印当前时间为:" + date);
    }
}
创建自定义Scheduler监听器类
public class MySchedulerListener implements SchedulerListener {
    @Override
    public void jobScheduled(Trigger trigger) {
        System.out.println("部署JobDetail");
    }

    @Override
    public void jobUnscheduled(TriggerKey triggerKey) {
        System.out.println("卸载JobDetail");
    }

    @Override
    public void triggerFinalized(Trigger trigger) {
        System.out.println("触发器不会再被触发了");
    }

    @Override
    public void triggerPaused(TriggerKey triggerKey) {
        System.out.println("触发器被暂停");
    }

    @Override
    public void triggersPaused(String s) {
        System.out.println("触发器组被暂停");
    }

    @Override
    public void triggerResumed(TriggerKey triggerKey) {
        System.out.println("触发器从暂停中恢复");
    }

    @Override
    public void triggersResumed(String s) {
        System.out.println("触发器组从暂停中恢复");
    }

    @Override
    public void jobAdded(JobDetail jobDetail) {
        System.out.println("添加任务");
    }

    @Override
    public void jobDeleted(JobKey jobKey) {
        System.out.println("删除任务");
    }

    @Override
    public void jobPaused(JobKey jobKey) {
        System.out.println("任务被暂停");
    }

    @Override
    public void jobsPaused(String s) {
        System.out.println("任务组被暂停");
    }

    @Override
    public void jobResumed(JobKey jobKey) {
        System.out.println("暂停的任务被恢复");
    }

    @Override
    public void jobsResumed(String s) {
        System.out.println("暂停的任务组被恢复");
    }

    @Override
    public void schedulerError(String s, SchedulerException e) {
        System.out.println("触发器触发后发生了严重的错误");
    }

    @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("调度器数据被清除");
    }
}
创建调度器执行任务并注册监听(没有全局局部之分的)
public class TriggerListenerDemo {
    public static void main(String[] args) throws SchedulerException {
        // 创建调度器,通过默认工厂获取
        Scheduler scheduler = StdSchedulerFactory.getDefaultScheduler();
        // 创建任务实例,与JobListener绑定
        JobDetail jobDetail = JobBuilder.newJob(JobListenerJob.class)
                // 设置任务名称及任务分组
                .withIdentity("job1","group1")
                .build();
        // 创建触发器
        Trigger trigger = TriggerBuilder.newTrigger()
                // 设置触发器名称及触发器分组
                .withIdentity("trigger1","group1")
                // 设置触发条件,具体的触发器类型,每两秒触发一次
                .withSchedule(SimpleScheduleBuilder.repeatSecondlyForever(2))
                .build();
        // 调度任务与触发器
        scheduler.scheduleJob(jobDetail,trigger);
        // 创建并注册一个调度器监听器
        scheduler.getListenerManager().addSchedulerListener(new MySchedulerListener());
        // 启动调度器
        scheduler.start();
    }
}

监听器移除

三种监听器都用的remove方法进行移除
需要注意参数的给定
如移除调度器监听器时,需要给定对应的监听器对象

scheduler.getListenerManager().removeJobListener();
scheduler.getListenerManager().removeTriggerListener();
scheduler.getListenerManager().removeSchedulerListener();

Quartz整合SSM

Quartz整合SpringBoot

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值