Quartz定时任务[通俗易懂]

一、Quartz的核心概念1.任务jobjob就是想要实现的任务类,每一个job必须实现job接口,且实现接口中的excute()方法。2.触发器TriggerTrigger为你执行任务的触发器,可以设置特定时间执行该任务Trigger主要包含SimpleTrigger和CronTrigger两种3.调度器SchedulerScheduler为任务的调度器,它会将任务job及触发器…

大家好,又见面了,我是你们的朋友全栈君。

一、Quartz的核心概念

1.任务job

job就是想要实现的任务类,每一个job必须实现job接口,且实现接口中的 excute()方法。

2.触发器Trigger

Trigger为你执行任务的触发器,可以设置特定时间执行该任务
Trigger主要包含SimpleTrigger和CronTrigger两种

3.调度器Scheduler

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

4.Quartz的体系结构

在这里插入图片描述

5.Quartz的核心组件

在这里插入图片描述

二、Quartz的基本功能

pom.xml文件中添加quartz相关jar包的坐标

<dependency>
    <groupId>org.quartz-scheduler</groupId>
    <artifactId>quartz</artifactId>
    <version>2.3.0</version>
</dependency>

<dependency>
    <groupId>org.quartz-scheduler</groupId>
    <artifactId>quartz-jobs</artifactId>
    <version>2.2.1</version>
</dependency>

1.首先创建一个Myjob工作类并实现Job接口,并重写里面的execute方法,为了直观的观察定时任务,我们在里面输出当前时间

/** * Created by yan on 2019/1/27. */
public class MyJob implements Job { 
   
    @Override
    public void execute(JobExecutionContext context) throws JobExecutionException { 
   
        System.out.print("quartz:I coming--------");
        System.out.println((new SimpleDateFormat("yyyy-MM-dd HH-mm-ss")).format(new Date()));
    }
}

2.创建一个MyScheduler

/** * Created by yan on 2019/1/27. */
public class MyScheduler { 
   
    public static void main(String[] args) { 
   
        //创建一个JobDetail实例
        JobDetail jobDetail = JobBuilder.newJob(MyJob.class)
                .withIdentity("jobDetail","group1")//jobdetail的唯一标示
                .build();

        //创建一个Trigger实例
        Trigger trigger = TriggerBuilder.newTrigger().withIdentity("trigger","group1")//Trigger的唯一标识
                .startNow()    //简单的定时器 每2秒钟执行一次 执行到永远
                .withSchedule(SimpleScheduleBuilder.simpleSchedule().withIntervalInSeconds(2).repeatForever())
                .build();

        //创建Scheduler实例
        //通过SchedulerFactory创建
        SchedulerFactory schedulerFactory = new StdSchedulerFactory();
        try { 
   
            Scheduler scheduler = schedulerFactory.getScheduler();
            //使用scheduler将jobDetail和trigger结合起来
            scheduler.scheduleJob(jobDetail,trigger);
            //开始
            scheduler.start();

        } catch (SchedulerException e) { 
   
            e.printStackTrace();
        }

    }
}

OutPut:
在这里插入图片描述

Scheduler实例创建的两种方式

//通过SchedulerFactory创建
SchedulerFactory schedulerFactory = new StdSchedulerFactory();
scheduler = schedulerFactory.getScheduler();

//通过StdSchedulerFactory创建
Scheduler scheduler = StdSchedulerFactory.getDefaultScheduler();//类名.方法(static)

JobDataMap 介绍

JobDataMap介绍
1).

  • 在进行任务调度时,JobDataMap存储在JobExecutionContext中 ,非常方便获取。
  • JobDataMap可以用来装载任何可序列化的数据对象,当job实例对象被执行时这些参数对象会传递给它。
  • JobDataMap实现了JDK的Map接口,并且添加了非常方便的方法用来存取基本数据类型。
    我们从底层代码中查看JobDataMap Implement Map
    在这里插入图片描述在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    JobDatamap Implement Map 确认无误
    2).
    Job实现类中添加setter方法对应JobDataMap的键值,Quartz框架默认的JobFactory实现类在初始化job实例对象时会
    自动地调用这些setter方法。
    3).
    如果遇到同名的key,Trigger中的.usingJobData(“message”, “新年快乐”)
    会覆盖
    JobDetail的.usingJobData(“message”, “新年不快乐”)。
//jobDetail中添加JobDataMap
.usingJobData("message","祝大家新年快乐")
//trigger中添加JobDataMap
.usingJobData("message","祝大家新年长胖20斤")
//MyJob实现类中 private message ,并给set方法
private String message;

    public void setMessage(String message) { 
   
        this.message = message;
    }
System.out.println(message);

运行OutPut:
在这里插入图片描述

有状态Job和无状态Job

有状态的Job可以理解为多次Job调用期间可以持有一些状态信息,这些状态信息存储在JobDataMap中,
而默认的无状态job每次调用时都会创建一个新的JobDataMap。

//jobDetail中添加JobDataMap
.usingJobData("count",1)
//MyJob中private count 并给set方法
private Integer count;

    public void setCount(Integer count) { 
   
        this.count = count;
    }
count++;
System.out.println(count);
context.getJobDetail().getJobDataMap().put("count",count);

OutPut:
在这里插入图片描述
默认给定无状态的Job,可以通过注解的方式改变Job的状态为有状态的Job

//在MyJob类上添加
@PersistJobDataAfterExecution		//可以将无状态的job转变为有状态的job

在这里插入图片描述

Trigger触发器

上面的代码我们使用的是SimpleTrigger(简单的触发器),这种触发器只能完成一定频率的触发任务(即:每隔多长时间触发),这显然不能满足我们对定时任务的需求,因此CronTrigger便横空出世

如果你需要像日历那样按日程来触发任务,而不是像SimpleTrigger 那样每隔特定的间隔时间触发,CronTriggers通常比SimpleTrigger更有用,因为它是基于日历的作业调度器。

使用CronTrigger,你可以指定诸如“每隔周五的晚上8:00”,或者“每个工作日的9:30”或者“从每个周一、周三、周五的上午9:00到上午10:00之间每隔五分钟”这样日程安排来触发。甚至,象SimpleTrigger一样,CronTrigger也有一个startTime以指定日程从什么时候开始,也有一个(可选的)endTime以指定何时日程不再继续。
在这里插入图片描述
当然这些表达式是不需要死记硬背的,我们可以通过网上的Cron表达式生成器进行转换
Cron表达式转换
在这里插入图片描述

//SimpleTrigger的创建
.withSchedule(SimpleScheduleBuilder.simpleSchedule().withIntervalInSeconds(2).repeatForever()
//CronTrigger的创建
.withSchedule(CronScheduleBuilder.cronSchedule("0 13 17 ? 1 ? *"))

Quartz监听

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

1.JobListener
public class MyJobListener implements JobListener { 
   
    //获取listener的名称
    @Override
    public String getName() { 
   
        String name = getClass().getSimpleName();
        return name;
    }
    //Scheduler在JobDetail将要被执行时调用这个方法
    @Override
    public void jobToBeExecuted(JobExecutionContext context) { 
   
        String jobName = context.getJobDetail().getKey().getName();
        System.out.println("Job的名称是:"+jobName+"Scheduler在JobDetail将要被执行时调用这个方法");
    }
    //Scheduler在JobDetail即将被执行,但又被TriggerListerner否决时会调用该方法
    @Override
    public void jobExecutionVetoed(JobExecutionContext context) { 
   
        String jobName = context.getJobDetail().getKey().getName();
        System.out.println("Job的名称是:"+jobName+"Scheduler在JobDetail即将被执行,但又被TriggerListerner否决时会调用该方法");
    }
    //Scheduler在JobDetail被执行之后调用这个方法
    @Override
    public void jobWasExecuted(JobExecutionContext context, JobExecutionException jobException) { 
   
        String jobName = context.getJobDetail().getKey().getName();
        System.out.println("Job的名称是:"+jobName+"Scheduler在JobDetail被执行之后调用这个方法");
    }
}
2.TriggerListener
public class MyTriggerListener implements TriggerListener { 
   

    private String name;

    public MyTriggerListener(String name) { 
   
        this.name = name;
    }

    @Override
    public String getName() { 
   
        return name;
    }
    //triggerFired方法:当与监听器相关联的Trigger被触发,Job上的execute()方法将被执行时,Scheduler就调用该方法。
    @Override
    public void triggerFired(Trigger trigger, JobExecutionContext context) { 
   
        String triggerName = trigger.getKey().getName();
        System.out.println(triggerName + " 被触发");
    }
    //vetoJobExecution方法:在 Trigger 触发后,Job 将要被执行时由 Scheduler
    // 调用这个方法。TriggerListener 给了一个选择去否决 Job 的执行。
    // 假如这个方法返回 true,这个 Job 将不会为此次 Trigger 触发而得到执行。
    @Override
    public boolean vetoJobExecution(Trigger trigger, JobExecutionContext context) { 
   
        String triggerName = trigger.getKey().getName();
        System.out.println(triggerName + " 没有被触发");
        return true; // true:表示不会执行Job的方法
    }
    //triggerMisfired方法:Scheduler 调用这个方法是在 Trigger 错过触发时。
    // 你应该关注此方法中持续时间长的逻辑:在出现许多错过触发的 Trigger 时,长逻辑会导致骨牌效应。你应当保持这上方法尽量的小。
    @Override
    public void triggerMisfired(Trigger trigger) { 
   
        String triggerName = trigger.getKey().getName();
        System.out.println(triggerName + " 错过触发");
    }
    //triggerComplete方法:Trigger 被触发并且完成了 Job 的执行时,Scheduler 调用这个方法。
    @Override
    public void triggerComplete(Trigger trigger, JobExecutionContext context, Trigger.CompletedExecutionInstruction triggerInstructionCode) { 
   
        String triggerName = trigger.getKey().getName();
        System.out.println(triggerName + " 完成之后触发");
    }
}
3.SchedulerListener(重写的方法很多,我也不清楚怎么使用)
1) jobScheduled方法:用于部署JobDetail时调用

2) jobUnscheduled方法:用于卸载JobDetail时调用

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

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

5) triggersResumed方法:Scheduler 调用这个方法是发生成一个 Trigger 或 Trigger 组从暂停中恢复时。假如是 Trigger 组的话,假如是 Trigger 组的话,triggerName 参数将为 null。参数将为 null。
6) jobsPaused方法:当一个或一组 JobDetail 暂停时调用这个方法。
7) jobsResumed方法:当一个或一组 Job 从暂停上恢复时调用这个方法。假如是一个 Job 组,jobName 参数将为 null。
8) schedulerError方法:在 Scheduler 的正常运行期间产生一个严重错误时调用这个方法。
9) schedulerStarted方法:当Scheduler 开启时,调用该方法
10) schedulerInStandbyMode方法: 当Scheduler处于StandBy模式时,调用该方法
11) schedulerShutdown方法:当Scheduler停止时,调用该方法
12) schedulingDataCleared方法:当Scheduler中的数据被清除时,调用该方法。
public class MySchedulerListener implements SchedulerListener { 
   
    @Override
    public void jobScheduled(Trigger trigger) { 
   

    }

    @Override
    public void jobUnscheduled(TriggerKey triggerKey) { 
   

    }

    @Override
    public void triggerFinalized(Trigger trigger) { 
   

    }

    @Override
    public void triggerPaused(TriggerKey triggerKey) { 
   

    }

    @Override
    public void triggersPaused(String triggerGroup) { 
   

    }

    @Override
    public void triggerResumed(TriggerKey triggerKey) { 
   

    }

    @Override
    public void triggersResumed(String triggerGroup) { 
   

    }

    @Override
    public void jobAdded(JobDetail jobDetail) { 
   

    }

    @Override
    public void jobDeleted(JobKey jobKey) { 
   

    }

    @Override
    public void jobPaused(JobKey jobKey) { 
   

    }

    @Override
    public void jobsPaused(String jobGroup) { 
   

    }

    @Override
    public void jobResumed(JobKey jobKey) { 
   

    }

    @Override
    public void jobsResumed(String jobGroup) { 
   

    }

    @Override
    public void schedulerError(String msg, SchedulerException cause) { 
   

    }

    @Override
    public void schedulerInStandbyMode() { 
   

    }

    @Override
    public void schedulerStarted() { 
   

    }

    @Override
    public void schedulerStarting() { 
   

    }

    @Override
    public void schedulerShutdown() { 
   

    }

    @Override
    public void schedulerShuttingdown() { 
   

    }

    @Override
    public void schedulingDataCleared() { 
   

    }
}

Quartz.properties

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

我们也可以在项目的资源下添加quartz.properties文件,去覆盖底层的配置文件。

组成部分

  • 调度器属性

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

org.quartz.scheduler.instanceId属性和前者一样,也允许任何字符串,但这个值必须在所有调度器实例中是唯一的,尤其是在一个集群环境中,作为集群的唯一key。假如你想Quartz帮你生成这个值的话,可以设置为AUTO。

  • 线程池属性

threadCount

处理Job的线程个数,至少为1,但最多的话最好不要超过100,在多数机器上设置该值超过100的话就会显得相当不实用了,特别是在你的 Job 执行时间较长的情况下

threadPriority

线程的优先级,优先级别高的线程比级别低的线程优先得到执行。最小为1,最大为10,默认为5

org.quartz.threadPool.class

#===============================================================     
	#Configure Main Scheduler Properties     调度器属性
	#===============================================================  
	#调度器的实例名     
	org.quartz.scheduler.instanceName = QuartzScheduler     
	#调度器的实例ID,大多数情况设置为auto即可  
	org.quartz.scheduler.instanceId = AUTO     
	 ====================================     
	#Configure JobStore 作业存储设置
	#===============================================================      
	#要使 Job 存储在内存中需通过设置  org.quartz.jobStrore.class 属性为 org.quartz.simpl.RAMJobStore 
	org.quartz.jobStore.class = org.quartz.simpl.RAMJobStore     
	 
	#===============================================================     
	#Configure Plugins    插件配置 
	#===============================================================       
	org.quartz.plugin.jobInitializer.class =       
	org.quartz.plugins.xml.JobInitializationPlugin       
	      
	org.quartz.plugin.jobInitializer.overWriteExistingJobs = true      
	org.quartz.plugin.jobInitializer.failOnFileNotFound = true      
	org.quartz.plugin.jobInitializer.validating=false  

	#===============================================================     
	#Configure ThreadPool     线程池属性
	#===============================================================   
	#处理Job的线程个数,至少为1,但最多的话最好不要超过100,在多数机器上设置该值超过100的话就会显得相当不实用了,特别是在你的 Job 执行时间较长的情况下
	org.quartz.threadPool.threadCount =  5     
	#线程的优先级,优先级别高的线程比级别低的线程优先得到执行。最小为1,最大为10,默认为5
	org.quartz.threadPool.threadPriority = 5 
	#一个实现了 org.quartz.spi.ThreadPool 接口的类,Quartz 自带的线程池实现类是 org.quartz.smpl.SimpleThreadPool      
	org.quartz.threadPool.class = org.quartz.simpl.SimpleThreadPool     
	 
	#===========================

基本功能测试完成,下面可以学习一下spring整合quartz

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/125582.html原文链接:https://javaforall.net

(0)
上一篇 2022年4月18日 下午4:20
下一篇 2022年4月18日 下午4:40


相关推荐

  • Rebar:Erlang构建工具

    Rebar:Erlang构建工具本文转载自 http www cnblogs com panfeng412 archive 2011 08 14 2137990 html 作者 panfeng412 转载请注明该声明 Rebar 是一款 Erlang 的构建工具 使用它可以方便的编译 测试 erlang 程序 内联驱动和打包 Erlang 发行版本 Rebar 是一个独立的 erlang 脚本 所以使用 Rebar 发布程序非常简单 甚至可以

    2026年3月17日
    2
  • PostMan的安装和使用教程[通俗易懂]

    PostMan的安装和使用教程[通俗易懂]postman的下载官网:https://www.getpostman.com/downloads/创建账号或者用谷歌浏览器账号登录一个demo了解一下我做的是一个app,后台使用java做的,app通过ajax来请求后台,但是我不知道后台有没有请求成功!因此需要一个测试接口的东西测试我做的接口有没有问题我的app里面的ajax是这样写的api.aja…

    2026年1月17日
    6
  • 软件设计师考试1

    软件设计师考试1最近在准备软考 为了便于自己记忆 就整理了一下下 希望对大家有帮助 1 虚拟存储器有主存和辅存两级存储器组成 2 中断向量可描述中断服务程序的入口地址 3 多重中断时 每次中断出现的断点都必须保存起来 断点可以保存在堆栈中 由于堆栈先进后出的特点 依次将程序的断点压入堆栈中 出栈时 按相反顺序便可准确返回到程序间断处 4 由 DMA 直接内存存取 控制外设与主存之间的数据传送 无须 CPU

    2026年3月17日
    2
  • Eth-trunk 链路聚合技术_eth-trunk配置

    Eth-trunk 链路聚合技术_eth-trunk配置链路聚合模式、Eth-Trunk的优势、Eth-Trunk接口配置流程、LACP抢占机制、Eth-Trunk接口负载分担、Eth-Trunk接口配置注意事项

    2025年7月15日
    7
  • windows 如何安装ffmpeg[通俗易懂]

    windows 如何安装ffmpeg

    2022年2月20日
    73

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号