写点什么

SpringBoot 整合 Quartz

作者:陈老老老板
  • 2022-11-25
    北京
  • 本文字数:5189 字

    阅读完需:约 17 分钟

SpringBoot整合Quartz

陈老老老板

说明:工作了,学习一些新的技术栈和工作中遇到的问题,边学习边总结,各位一起加油。需要注意的地方都标红了,还有资源的分享. 一起加油。本文是介绍 Quartz 与 SpringBoot 整合



一、Quartz 简介

1.简介

可以先看一下 Quartz 官网:Quartz官网说明:在整合之前先学习一下什么是 QUartz:Quartz 是一个功能丰富的开源作业调度库,可以集成到几乎任何 Java 应用程序中,Quartz 是 OpenSymphony 开源组织在 Job Scheduling 领域又一个开源项目,是完全由 Java 开发的一个开源任务日程管理系统,“任务进度管理器”就是一个在预先确定(被纳入日程)的时间到达时,负责执行(或者通知)其他软件组件的系统。 Quartz 是一个开源的作业调度框架,它完全由 Java 写成,并设计用于 J2SE 和 J2EE 应用中,它提供了巨大的灵活性而不牺牲简单性。(也就是定时任务,确定好时间,就按指定时间执行)

2.核心概念:

  • 工作(Job):用于定义具体执行的工作,是一个==接口==,只定义一个方法==execute()== 方法,在实现接口的 execute() 方法中编写所需要定时执行的 Job。

  • 工作明细(JobDetail):用于描述定时工作相关的信息,包括了任务的==唯一标识和具体要执行的任务==,可以通过 JobDataMap 往任务中传递数据

  • 触发器(Trigger):描述了工作明细与调度器的对应关系,是一个==类==,描述触发 Job (工作)执行的==时间触发规则==。说明:主要有 SimpleTrigger 和 CronTrigger 这两个子类。SimpleTrigger 当且仅当需调度一次或者以固定时间间隔周期执行调度,是最适合的选择;CronTrigger 则可以通过 Cron 表达式定义出各种复杂时间规则的调度方案:(如工作日周一到周五的 15:00 ~ 16:00 执行调度等)

  • 调度器(Scheduler):用于描述触发工作的==执行规则==,通常使用==cron 表达式==定义规则。通过 Trigger 和 JobDetail 可以用来调度、暂停和删除任务。调度器就相当于一个容器,装载着任务和触发器,该类是一个==接口==,代表一个 Quartz 的独立运行容器,Trigger 和 JobDetail 可以注册到 Scheduler 中,两者在 Scheduler 中拥有各自的组及名称,组及名称是 Scheduler 查找定位容器中某一对象的依据,Trigger 的组及名称必须唯一,JobDetail 的组和名称也必须唯一(但可以和 Trigger 的组和名称相同,因为它们是不同类型的)


注:简单说就是你定时干什么事情,这就是工作,工作不可能就是一个简单的方法,还要设置一些明细信息。

3.作业存储类型

  • RAMJobStore:==RAM 也就是内存==,默认情况下 Quartz 会将任务调度存储在内存中,这种方式性能是最好的,因为内存的速度是最快的。不好的地方就是数据缺乏持久性,但程序崩溃或者重新发布的时候,所有运行信息都会丢失

  • JDBC 作业存储:存到数据库之后,可以做单点也可以做集群,==当任务多了之后,可以统一进行管理,随时停止、暂停、修改任务==。关闭或者重启服务器,运行的信息都不会丢失。缺点就是运行速度快慢取决于连接数据库的快慢

二、SpringBoot 整合 Quartz

这里演示使用的是第一种内存存储作业信息,较为简单,只需在 properties 中设置即可。

1、创建项目


2.添加依赖

<font color="red"><b><b><b><code class="language-xml"><dependency>    <groupId>org.springframework.boot</groupId>    <artifactId>spring-boot-starter-quartz</artifactId></dependency></code></b></b></b></font>
复制代码


整体依赖


<font color="red"><b><b><b><code class="language-xml"> <dependencies>        <dependency>            <groupId>org.springframework.boot</groupId>            <artifactId>spring-boot-starter</artifactId>        </dependency>
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency>
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-quartz</artifactId> </dependency> </dependencies></code></b></b></b></font>
复制代码

2.配置文件

(1)创建 quartz.properties

注:默认情况下,Quartz 会加载 classpath 下的 quartz.properties 作为配置文件。如果找不到,则会使用 quartz 框架自己 jar 包下 org/quartz 底下的 quartz.properties 文件


<font color="red"><b><b><b><code class="language-yaml">#主要分为scheduler、threadPool、jobStore、dataSource等部分

org.quartz.scheduler.instanceId=AUTOorg.quartz.scheduler.instanceName=DefaultQuartzScheduler#如果您希望Quartz Scheduler通过RMI作为服务器导出本身,则将“rmi.export”标志设置为true#在同一个配置文件中为'org.quartz.scheduler.rmi.export'和'org.quartz.scheduler.rmi.proxy'指定一个'true'值是没有意义的,如果你这样做'export'选项将被忽略org.quartz.scheduler.rmi.export=false#如果要连接(使用)远程服务的调度程序,则将“org.quartz.scheduler.rmi.proxy”标志设置为true。您还必须指定RMI注册表进程的主机和端口 - 通常是“localhost”端口1099org.quartz.scheduler.rmi.proxy=falseorg.quartz.scheduler.wrapJobExecutionInUserTransaction=false

#实例化ThreadPool时,使用的线程类为SimpleThreadPoolorg.quartz.threadPool.class=org.quartz.simpl.SimpleThreadPool#threadCount和threadPriority将以setter的形式注入ThreadPool实例#并发个数 如果你只有几个工作每天触发几次 那么1个线程就可以,如果你有成千上万的工作,每分钟都有很多工作 那么久需要50-100之间.#只有1到100之间的数字是非常实用的org.quartz.threadPool.threadCount=5#优先级 默认值为5org.quartz.threadPool.threadPriority=5#可以是“true”或“false”,默认为falseorg.quartz.threadPool.threadsInheritContextClassLoaderOfInitializingThread=true

#在被认为“misfired”(失火)之前,调度程序将“tolerate(容忍)”一个Triggers(触发器)将其下一个启动时间通过的毫秒数。默认值(如果您在配置中未输入此属性)为60000(60秒)org.quartz.jobStore.misfireThreshold=5000# 默认存储在内存中,RAMJobStore快速轻便,但是当进程终止时,所有调度信息都会丢失#org.quartz.jobStore.class=org.quartz.simpl.RAMJobStore
#持久化方式,默认存储在内存中,此处使用数据库方式org.quartz.jobStore.class=org.quartz.impl.jdbcjobstore.JobStoreTX#您需要为JobStore选择一个DriverDelegate才能使用。DriverDelegate负责执行特定数据库可能需要的任何JDBC工作# StdJDBCDelegate是一个使用“vanilla”JDBC代码(和SQL语句)来执行其工作的委托,用于完全符合JDBC的驱动程序org.quartz.jobStore.driverDelegateClass=org.quartz.impl.jdbcjobstore.StdJDBCDelegate#可以将“org.quartz.jobStore.useProperties”配置参数设置为“true”(默认为false),以指示JDBCJobStore将JobDataMaps中的所有值都作为字符串,#因此可以作为名称 - 值对存储而不是在BLOB列中以其序列化形式存储更多复杂的对象。从长远来看,这是更安全的,因为您避免了将非String类序列化为BLOB的类版本问题org.quartz.jobStore.useProperties=true#表前缀org.quartz.jobStore.tablePrefix=QRTZ_#数据源别名,自定义org.quartz.jobStore.dataSource=qzDS</code></b></b></b></font>
复制代码


关于quartz全部配置详情可以点击查看注:其实不需要这么多想简单入门可以按如下的配置 quartz.properties


<font color="red"><b><b><b><code class="language-yaml">org.quartz.scheduler.instanceName = MySchedulerorg.quartz.threadPool.threadCount = 3org.quartz.jobStore.class = org.quartz.simpl.RAMJobStore</code></b></b></b></font>
复制代码


  • org.quartz.scheduler.instanceName - 设置调度程序 scheduler 的名称为 MyScheduler

  • org.quartz.threadPool.threadCount - 线程里设置了 3 个线程,意味着最多同时运行 3 个 job

  • org.quartz.jobStore.class - 指定为 RAMJobStore,表示所有 Quartz 的数据,包括 jobDetail、trigger 等均运行在内存中(而不是数据库中)。 如果你想 Quartz 使用你的数据库,还是建议你在使用数据库配置之前使用 RAMJobStore 进行工作。通过使用一个数据库,你可以打开一个全新的维度,但在这之前,建议你使用 RAMJobStore。

3、定义任务 Bean,按照 Quartz 的开发规范制作,继承 QuartzJobBean

<font color="red"><b><b><b><code class="language-java">public class MyQuartz extends QuartzJobBean {    @Override    protected void executeInternal(JobExecutionContext context) throws JobExecutionException {    //这里是你想执行的任务信息    //可以使用context参数获取其他信息,联系上下文        System.out.println("quartz task run...");    }}</code></b></b></b></font>
复制代码

4、创建 Quartz 配置类,定义工作明细(JobDetail)与触发器的(Trigger)bean

<font color="red"><b><b><b><code class="language-java">@Configurationpublic class QuartzConfig {    @Bean    public JobDetail printJobDetail(){        //绑定具体的工作(newJob中的参数,就是要执行的Job类)        //storeDurably()用来做持久化        return JobBuilder.newJob(MyQuartz.class).storeDurably().build();    }    @Bean    public Trigger printJobTrigger(){    //  创建cron表达式表示什么时间执行,一般日期和星期不一起出现                   每两秒执行一次        ScheduleBuilder schedBuilder = CronScheduleBuilder.cronSchedule("0/2 * * * * ?");        //绑定对应的工作明细   forJob中写上面JobDetail(任务明细)的方法名        return  TriggerBuilder.newTrigger().forJob(printJobDetail()).withSchedule(schedBuilder).build();    }}</code></b></b></b></font>
复制代码


CronScheduleBuilder.cronSchedule("0/5 * * * * ?");这里使用的是 cron 表达式,下一篇博客会有详解。


工作明细中要设置对应的具体工作,使用 newJob()操作传入对应的工作任务类型即可。

5.测试

点击启动类,启动项目,就会发现每两秒执行一次。



注:触发器需要绑定任务,使用 forJob()操作传入绑定的工作明细对象。此处可以为工作明细设置名称然后使用名称绑定,也可以直接调用对应方法绑定。触发器中最核心的规则是执行时间,此处使用调度器定义执行时间,执行时间描述方式使用的是 cron 表达式。有关 cron 表达式的规则,各位小伙伴可以去参看相关课程学习,略微复杂,而且格式不能乱设置,不是写个格式就能用的,写不好就会出现冲突问题。

三、简单定时任务使用 Task

说明:spring 根据定时任务的特征,将定时任务的开发简化到了极致。要做定时任务总要告诉容器,然后定时执行什么任务直接告诉对应的 bean 什么时间执行就行了。

1、开启定时任务功能,在引导类上开启定时任务功能的开关,使用注解 @EnableScheduling

<font color="red"><b><b><b><code class="language-java">@SpringBootApplication//开启定时任务功能@EnableSchedulingpublic class Springboot22TaskApplication {    public static void main(String[] args) {        SpringApplication.run(Springboot22TaskApplication.class, args);    }}</code></b></b></b></font>
复制代码

2、定义 Bean,在对应要定时执行的操作上方,使用注解 @Scheduled 定义执行的时间,执行时间的描述方式还是 cron 表达式

<font color="red"><b><b><b><code class="language-java">@Componentpublic class MyBean {    @Scheduled(cron = "0/1 * * * * ?")    public void print(){        System.out.println(Thread.currentThread().getName()+" :spring task run...");    }}</code></b></b></b></font>
复制代码


<font color="red"><b><b><b><code>    如何想对定时任务进行相关配置,可以通过配置文件进行</code></b></b></b></font>
复制代码


<font color="red"><b><b><b><code class="language-yaml">spring:  task:       scheduling:      pool:           size: 1              # 任务调度线程池大小 默认 1      thread-name-prefix: ssm_        # 调度线程名称前缀 默认 scheduling-              shutdown:          await-termination: false    # 线程池关闭时等待所有任务完成          await-termination-period: 10s  # 调度线程关闭前最大等待时间,确保最后一定关闭</code></b></b></b></font>
复制代码


总结:定时任务是工作中必须掌握的内容。希望对您有帮助,感谢阅读结束语:裸体一旦成为艺术,便是最圣洁的。道德一旦沦为虚伪,便是最下流的。勇敢去做你认为正确的事,不要被世俗的流言蜚语所困扰。


发布于: 2022-11-25阅读数: 21
用户头像

奇安信开发工程师,有问题可以私聊我! 2019-03-16 加入

还未添加个人简介

评论

发布
暂无评论
SpringBoot整合Quartz_定时任务_陈老老老板_InfoQ写作社区