SpringBoot——Quartz 定时任务

优质博文:IT-BLOG-CN

一、Scheduled 定时任务

【1】添加Scheduled相关依赖,它是Spring自带的一个jar包因此引入Spring的依赖:

<dependency><groupId>org.springframework</groupId><artifactId>spring-context-support</artifactId>
</dependency>

【2】导入依赖之后,就可以在Maven Dependencies中看到相关的依赖,如下:

【3】编写定时任务类:重点是@Scheduled注解和cron属性;

/*** Scheduled 定时任务* 定时任务不属于持久层也不属于业务层,所以应该使用 @Component 进行标记* @author Administrator**/
@Component
public class ScheduledDemo {/*** 定时任务方法,如果是定时任务方法,需要添加 scheduled注解* scheduled:表示当前方法就是一个定时任务方法* cron属性: 定时任务触发时间的一个字符串表达式* 触发条件:每2秒触发一次,博客后面重点说 cron 表达式*/@Scheduled(cron="0/2 * * * * ?")public void scheduledMethod() {System.out.println("定时任务"+new Date());}
}

【4】在启动类中开启定时任务的启动:@EnableScheduling注解

@SpringBootApplication
@EnableScheduling
public class ScheduledApplication {public static void main(String[] args) {SpringApplication.run(ScheduledApplication.class, args);}
}

【5】cron 表达式:是一个字符串,分为 6 或 7 个域(建议使用 6个域),每个域代表一个含义 :
 ■ 7个域:Seconds Minutes Hours Day Month Week Year (秒、分、小时、月份中的日期、月分、星期中的日期、年)
 ■ 6个域(少一个 Year):Seconds Minutes Hours Day Month Week

【6】各cron 字段的含义:星期和日是有冲突的,一般会舍掉一个。表达式对特殊字符的大小写不敏感,对代表星期的缩写英文大小写也不敏感;

位置时间域名允许值允许的特殊字符
10-59, - * /
2分钟0-59, - * /
3小时0-23, - * /
40-31, - * / ? L W C
51-12, - * /
6星期1-7, - * / ? L C #
71970-2099, - * /

①、星号(*):可用在所有字段中,表示对应时间域的每一个时刻。例如在秒时间域中表示每一秒;
②、问号(?):该字段只在星期和日期域中使用,它通常指定为“无意义的值”,相当于一个占位符;
③、减号(-):表示的是一个范围,如在小时字段中使用1-3,则表示 1,2,3点都执行;
④、逗号(,):表示一个列表值,如在秒域中使用 12,15表示第12秒和第15秒触发跑批;
⑤、斜杠(/):x/y 表示一个等步长序列,x为起始值,y为增量步长值,例如秒中使用 0/2 表示从0秒开始,没过2秒执行一次。
⑥、L:该字符只在日期和星期域中使用,但它在两个字段中的意思不同。L在日期字段表示月份的最后一天,如一月的31,二月的28等,如果在星期域中表示星期六(7),但是如果L出现在星期字段里,而且前面有一个数值 X,则表示这个月的最后 X 天,例如:6L表示该月的最后星期五;
⑦、W:该字符只能出现在日期域中,表示离该日期最近的工作日,例如 15W:表示离该月15号最近的工作日,如果15号是星期六则匹配星期五 14号。如果15号是星期日则匹配星期一 16日。如果15号是星期三则匹配星期三 15号本身。但需要注意关联的匹配不能够跨月,例如15号是2月的最后一天星期日,应该向下配置3月1日,但是不能跨月,只能匹配2月26星期五(2月最后一个工作日)W只能指定单一日期,不能指定范围;
⑧、LW组合:在日期字段组合使用,表示当月的最后一个工作日;
⑨、#号:该字符只能在星期域中使用,表示当月某个工作日。如6#3:表示当月的第三个星期五。
⑩、C:该字符只在日期和星期中使用,表示“Calendar” 的意思,表示计划所关联的日期。如果日期没有被关联,则表示所有日期。例如5C在日期域中表示 5日以后的第一天。1C在星期域中表示星期日后的第一天。

二、Springboot 整合Quartz 定时任务框架

Quartz 是 OpenSymphony开源组织在 Job scheduling(任务调度)领域又一个开源项目,它可以与J2EE与J2SE应用程序相结合也可以单独使用。Quartz 可以用来创建简单或为运行十个,百个,甚至是好几万个 Jobs这样复杂的程序。Jobs 可以做成标准的 Java组件或 EJBs。Quartz是一个完全由 Java编写的开源作业调度框架。

【1】quartz 的 maven 依赖:

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

【2】 Job(任务:你要做什么事):

import org.quartz.Job;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;/***  定时任务类* @author zzx**/
public class QuartzDemo implements Job{/*** 任务触发时所执行的方法*/public void execute(JobExecutionContext context) throws JobExecutionException {System.out.println("任务调度"+new Date());}
}

【3】Trigger(触发器:什么时候去做):有两种形式进行表达,其中一种就是 cron 表达式

【4】scheduler(任务调度:你什么时候需要做什么事):将 job 与 Trigger 进行整合。下面是一个例子:

import org.quartz.CronScheduleBuilder;
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;public class QuartzMain {public static void main(String[] args) throws Exception {//1、Job(任务:你要做什么事),这里使用的是建造者模式JobDetail job = JobBuilder.newJob(QuartzDemo.class).build();//2、Trigger(触发器:什么时候去做),这里 triggerbuilder 也是用建造者模式封装。触发条件分为两种//3.1 第一种:简单的 trigger 触发时间,通过 Quartz 提供方法完成简单的重复调用。如下一个例子:每秒触发一次//Trigger build = TriggerBuilder.newTrigger().withSchedule(SimpleScheduleBuilder.repeatSecondlyForever()).build();//3.2 第二种:按照 cron 的表达式来给定触发时间Trigger trigger= TriggerBuilder.newTrigger().withSchedule(CronScheduleBuilder.cronSchedule("0/2 * * * * ?")).build();//3、scheduler(任务调度:你什么时候需要做什么事) 将上面的job 和 trigger进行组装 这里使用工厂模式。Scheduler defaultScheduler = StdSchedulerFactory.getDefaultScheduler();defaultScheduler.scheduleJob(job, trigger);//4、启动defaultScheduler.start();}
}

三、SpringBoot 整合 Quartz

【1】整合时相关依赖一下:

 <dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><scope>test</scope><exclusions><exclusion><groupId>org.junit.vintage</groupId><artifactId>junit-vintage-engine</artifactId></exclusion></exclusions></dependency><dependency><groupId>org.springframework</groupId><artifactId>spring-context-support</artifactId></dependency><!--Quartz 坐标--><dependency><groupId>org.quartz-scheduler</groupId><artifactId>quartz</artifactId><version>2.3.0</version><exclusions><exclusion><groupId>org.slf4j</groupId><artifactId>slf4j-api</artifactId></exclusion></exclusions></dependency><!--事务--><dependency><groupId>org.springframework</groupId><artifactId>spring-tx</artifactId></dependency>
</dependencies>

【2】 创建一个 Job 类:实现 Job 接口

/***  定时任务类* @author zzx**/
public class QuartzDemo implements Job {/*** 任务触发时所执行的方法*/public void execute(JobExecutionContext context) throws JobExecutionException {System.out.println("任务调度"+new Date());}
}

【3】编写 Quartz 的配置参数

import com.example.demo.scheduled.QuartzDemo;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.quartz.CronTriggerFactoryBean;
import org.springframework.scheduling.quartz.JobDetailFactoryBean;
import org.springframework.scheduling.quartz.SchedulerFactoryBean;
import org.springframework.scheduling.quartz.SimpleTriggerFactoryBean;/*** quartz 配置类*/
@Configuration
public class QuartzConfig {//1、创建 Job 对象@Beanpublic JobDetailFactoryBean jobDetailFactoryBean(){JobDetailFactoryBean jobDetailFactoryBean = new JobDetailFactoryBean();//通过反射的方式实例化 Job,并没有经过 spring 处理,所以依赖的对象不能通过 autowrite 注入jobDetailFactoryBean.setJobClass(QuartzDemo.class);return jobDetailFactoryBean;}//2、创建 Trigger 对象:也是分为两种:下面是创建一个简单的 trigger//这里需要传入 JOB 对象,作为参数关联
/*    @Beanpublic SimpleTriggerFactoryBean simpleTriggerFactoryBean(JobDetailFactoryBean jobDetailFactoryBean){SimpleTriggerFactoryBean simpleTriggerFactoryBean = new SimpleTriggerFactoryBean();//获取 JobDetail 关联simpleTriggerFactoryBean.setJobDetail(jobDetailFactoryBean.getObject());// 触发条件   该参数表示一个执行的毫秒数simpleTriggerFactoryBean.setRepeatInterval(2000);//设置重复次数simpleTriggerFactoryBean.setRepeatCount(5);return simpleTriggerFactoryBean;}*///通过 cron 表达式表示执行 trigger@Beanpublic CronTriggerFactoryBean cronTriggerFactoryBean(){CronTriggerFactoryBean cronTriggerFactoryBean = new CronTriggerFactoryBean();//获取 JobDetail 关联cronTriggerFactoryBean.setJobDetail(jobDetailFactoryBean().getObject());// 触发条件   该参数表示一个执行的毫秒数cronTriggerFactoryBean.setCronExpression("0/2 * * * * ?");return cronTriggerFactoryBean;}// 创建 scheduler 对象@Beanpublic SchedulerFactoryBean schedulerFactoryBean(){SchedulerFactoryBean schedulerFactoryBean = new SchedulerFactoryBean();//关联 TriggerschedulerFactoryBean.setTriggers(cronTriggerFactoryBean().getObject());return schedulerFactoryBean;}
}

【4】修改启动类

/*** 整合 Quartz*/
@SpringBootApplication
@EnableScheduling
public class ScheduledApplication {public static void main(String[] args) {SpringApplication.run(ScheduledApplication.class, args);}
}

四、Job 类中注入对象

【1】给 Job 类中注入 Service 类型的对象;

/***  定时任务类* @author zzx**/
public class QuartzDemo implements Job {@Autowiredprivate UserService userService;/*** 任务触发时所执行的方法*/public void execute(JobExecutionContext context) throws JobExecutionException {userService.test();System.out.println("任务调度"+new Date());}
}

【2】当运行时会出现空指针异常:userService 对象为空;

Caused by: java.lang.NullPointerException: nullat com.example.demo.scheduled.QuartzDemo.execute(QuartzDemo.java:25) ~[classes/:na]at org.quartz.core.JobRunShell.run(JobRunShell.java:202) ~[quartz-2.3.0.jar:na]... 1 common frames omitted

【3】没有注入 userService 的原因如下,它是通过反射创建 Job 对象,并没有经过 SpringIOC 处理,所以依赖的对象不能通过 autowrite 注入;

protected Object createJobInstance(TriggerFiredBundle bundle) throws Exception {Class<?> jobClass = bundle.getJobDetail().getJobClass();return ReflectionUtils.accessibleConstructor(jobClass, new Class[0]).newInstance(new Object[0]);
}

【4】解决方案:重写创建 Job 的方式:并进行实例化 @Component;

@Component
public class MyAdaptableJobFactory extends AdaptableJobFactory {//将对象添加到SpringIoc容器中,并且完成该对象的属性注入@Autowiredprivate AutowireCapableBeanFactory autowireCapableBeanFactory;/*** 该方法需要将实例化的 job 对象手动添加到SpringIOC 容器中并且完成实例化;*/@Overridepublic Object createJobInstance(TriggerFiredBundle bundle) throws Exception {Object jobInstance = super.createJobInstance(bundle);//将该对象加入 IOC 容器中autowireCapableBeanFactory.autowireBean(jobInstance);return jobInstance;}
}

【5】 将其注入到 Quartz 的配置类中,注入到 SchedulerFactoryBean 中;

// 修改 SchedulerFactoryBean 类,set 创建 job 的factory 类
@Bean
public SchedulerFactoryBean schedulerFactoryBean(MyAdaptableJobFactory myAdaptableJobFactory){SchedulerFactoryBean schedulerFactoryBean = new SchedulerFactoryBean();//关联 TriggerschedulerFactoryBean.setTriggers(cronTriggerFactoryBean().getObject());schedulerFactoryBean.setJobFactory(myAdaptableJobFactory);return schedulerFactoryBean;
}

【6】测试结果:

【7】解决方案:在 SSM 的项目中可以通过如下方式获取依赖对象;

//根据spring的配置文件得到ioc容器对象
ApplicationContext context =new ClassPathXmlApplicationContext("spring.xml");
Person person = context.getBean(Person.class);

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/188985.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

MySQL图书管理系统(49-94)源码

-- 九、 子查询 -- 无关子查询 -- 比较子查询&#xff1a;能确切知道子查询返回的是单值时&#xff0c;可以用>&#xff0c;<&#xff0c;&#xff0c;>&#xff0c;<&#xff0c;!或<>等比较运算符。 -- 49、 查询与“俞心怡”在同一个部门的读者的借…

诊所小程序开发,需要包含哪些功能,有什么注意事项?

开发一个诊所预约小程序&#xff0c;可以提高口腔诊所的服务效率和客户体验。那么&#xff0c;一般小程序的流程和功能包含哪些内容&#xff1f; 注册登录&#xff1a;用户可以快速授权并登录(可定制多种登录方式) 预约挂号&#xff1a;用户可以选择科室、医生、日期和时段进行…

Unity中Shader指令优化(编译后指令解析)

文章目录 前言一、我们先创建一个简单的Shader二、编译这个Shader&#xff0c;并且打开1、编译后注意事项2、编译平台 和 编译指令数3、顶点着色器用到的信息4、顶点着色器计算的核心部分5、片元着色器用到的信息6、片元着色器核心部分 前言 我们先读懂Shader编译后代码&#…

Linux命令与shell脚本编程大全【读书笔记 + 思考总结】

Linux命令与shell脚本编程大全 第 1 章 初识Linux shellLinux的组成及关系结构图是什么&#xff1f;Linux系统内核的作用是什么&#xff1f;内核的主要功能是什么&#xff1f;&#xff08;4点&#xff09;物理内存和虚拟内存是什么关系&#xff1f;内核如何实现虚拟内存&#x…

Ubuntu中MySQL安装与使用

一、安装教程&#xff1a;移步 二、通过sql文件创建表格&#xff1a; 首先进入mysql&#xff1a; mysql -u 用户 -p 回车 然后输入密码source sql文件&#xff08;路径&#xff09;;上面是sql语句哈&#xff0c;所以记得加分号。 sql文件部分截图&#xff1a; 创建成功后的部…

【android开发-04】android中activity的生命周期介绍

1&#xff0c;返回栈 android中使用任务task来管理activity&#xff0c;一个任务就是一组存放在栈里的活动的集合&#xff0c;这个栈被称为返回栈。栈是一种先进先出的数据结构。当我们启动一个新的活动&#xff0c;他会在返回栈中人栈&#xff0c;并处以栈顶的位置&#xff0…

浮点运算误差

输出所有形如aabb的4位完全平方数&#xff08;即前两位数字相等&#xff0c;后两位数字也相等&#xff09; 解决这个问题首先需要表示aabb这个变量&#xff0c;只需要定义一个变量n存储即可&#xff0c;另一个问题就是如何判断n是否为完全平方数&#xff1f; 第一种思路是先求出…

【Python表白系列】无限弹窗,满屏表白代码来啦(完整代码)

文章目录 满屏表白代码环境需求完整代码详细分析系列文章 满屏表白代码 环境需求 python3.11.4PyCharm Community Edition 2023.2.5pyinstaller6.2.0&#xff08;可选&#xff0c;这个库用于打包&#xff0c;使程序没有python环境也可以运行&#xff0c;如果想发给好朋友的话需…

rust中动态数组Vec的简单使用

在Rust中&#xff0c;Vector&#xff08;简称Vec&#xff09;是一个动态数组数据结构&#xff0c;它可以动态地增加或减少其容量。Vec是Rust标准库中的一个常见类型&#xff0c;非常适合用于存储和操作一系列相同类型的值。 Vec其实是一个智能指针&#xff0c;用于在堆上分配内…

2022年1月14日 Go生态洞察:Go 1.18 新教程探索

&#x1f337;&#x1f341; 博主猫头虎&#xff08;&#x1f405;&#x1f43e;&#xff09;带您 Go to New World✨&#x1f341; &#x1f984; 博客首页——&#x1f405;&#x1f43e;猫头虎的博客&#x1f390; &#x1f433; 《面试题大全专栏》 &#x1f995; 文章图文…

绩效考核管理项目|记录2

给界面添加筛选条件并且把搜索功能实现 这段代码写入搜索方法里面就能实现功能。 private void bingdgv(){//筛选项&#xff1a;用户名、职位代码、是否辞职string userName txtUserName.Text.Trim();int baseTypeId (int)base_cbx.SelectedValue;bool isStop isdel_ckb.Che…

【VMware相关】VMware vSphere存储方案

一、iSCSI存储 参考文档 VMware官方文档&#xff1a;配置iSCSI适配器和存储 华为配置指南&#xff1a;VMware ESXi下的主机连通性指南 1、配置说明 如下图所示&#xff0c;VMware配置iSCSI存储&#xff0c;需要将物理网卡绑定到VMKernel适配器上&#xff0c;之后再将VMKernel适…

Golang数据类型(数字型)

Go数据类型&#xff08;数字型&#xff09; Go中数字型数据类型大致分为整数&#xff08;integer&#xff09;、浮点数&#xff08;floating point &#xff09;和复数&#xff08;Complex&#xff09;三种 整数重要概念 整数在Go和Python中有较大区别&#xff0c;主要体现在…

opencv 图像边框

cv.copyMakeBorder() 图像设置边框或者填充

PyQt基础_012_对话框类控件QInputDialog

基本操作 import sys from PyQt5.QtCore import * from PyQt5.QtGui import * from PyQt5.QtWidgets import *class InputdialogDemo(QWidget):def __init__(self, parentNone):super(InputdialogDemo, self).__init__(parent)layout QFormLayout()self.btn1 QPushButton(&qu…

springboot+java校园自助洗衣机预约系统的分析与设计ssm+jsp

洗衣服是每个人都必须做的事情&#xff0c;而洗衣机更成为了人们常见的电器&#xff0c;但是单个洗衣机价格不菲&#xff0c;如果每人都买&#xff0c;就会造成资源的冗余。所有就出现了公用设备&#xff0c;随着时代的发展&#xff0c;很多公用都开始向着无人看守的自助模式经…

如何访问电脑的组策略编辑器?

如何打开组策略 如果我们使用的是 Win 10 系统&#xff0c;如何打开组策略&#xff1f;下面为大家总结了四种打开组策略编辑器的方法。 从搜索框打开 Win 10 策略组怎么打开&#xff1f;一个简单快速的方法就是使用 Windows 自带的搜索栏。我们可以向搜索框中输入“编辑组策…

【数电笔记】基本和复合逻辑运算

说明&#xff1a; 笔记配套视频来源&#xff1a;B站 基本逻辑运算 1. 与运算 &#xff08;and gate&#xff09; 2. 或运算 &#xff08;or gate&#xff09; 3. 非运算 &#xff08;not gate &#xff09; 复合逻辑运算 1. 与非运算&#xff08;nand&#xff09; 2. 或非运…

【动手学深度学习】(七)丢弃法

文章目录 一、理论知识二、代码实现2.1从零开始实现Dropout 【相关总结】np.random.uniform(low&#xff0c;high&#xff0c;size)astypetorch.rand() 一、理论知识 1.动机 一个好的模型需要对输入数据的扰动鲁棒 使用有噪音的数据等价于Tikhonov正则丢弃法&#xff1a;在层…

vivado实现分析与收敛技巧3-面向非工程用户的智能设计运行建议

要使用智能设计运行功能特性 &#xff0c; 需要 Vivado 工程。这是因为需要进行运行管理。以下指示信息解释了创建综合后工程的最简单方法。这些信息适用于以下流程的用户&#xff1a; • 非工程实现运行 • 使用较低版本的 Vivado 或第三方综合工具进行综合 访问智能设计…