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 对象
    @Bean
    public JobDetailFactoryBean jobDetailFactoryBean(){
        JobDetailFactoryBean jobDetailFactoryBean = new JobDetailFactoryBean();
        //通过反射的方式实例化 Job,并没有经过 spring 处理,所以依赖的对象不能通过 autowrite 注入
        jobDetailFactoryBean.setJobClass(QuartzDemo.class);
        return jobDetailFactoryBean;
    }

    //2、创建 Trigger 对象:也是分为两种:下面是创建一个简单的 trigger
    //这里需要传入 JOB 对象,作为参数关联
/*    @Bean
    public SimpleTriggerFactoryBean simpleTriggerFactoryBean(JobDetailFactoryBean jobDetailFactoryBean){
        SimpleTriggerFactoryBean simpleTriggerFactoryBean = new SimpleTriggerFactoryBean();
        //获取 JobDetail 关联
        simpleTriggerFactoryBean.setJobDetail(jobDetailFactoryBean.getObject());
        // 触发条件   该参数表示一个执行的毫秒数
        simpleTriggerFactoryBean.setRepeatInterval(2000);
        //设置重复次数
        simpleTriggerFactoryBean.setRepeatCount(5);
        return simpleTriggerFactoryBean;
    }*/

    //通过 cron 表达式表示执行 trigger
    @Bean
    public CronTriggerFactoryBean cronTriggerFactoryBean(){
        CronTriggerFactoryBean cronTriggerFactoryBean = new CronTriggerFactoryBean();
        //获取 JobDetail 关联
        cronTriggerFactoryBean.setJobDetail(jobDetailFactoryBean().getObject());
        // 触发条件   该参数表示一个执行的毫秒数
        cronTriggerFactoryBean.setCronExpression("0/2 * * * * ?");
        return cronTriggerFactoryBean;
    }

    // 创建 scheduler 对象
    @Bean
    public SchedulerFactoryBean schedulerFactoryBean(){
        SchedulerFactoryBean schedulerFactoryBean = new SchedulerFactoryBean();
        //关联 Trigger
        schedulerFactoryBean.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 {

    @Autowired
    private UserService userService;
    /**
     * 任务触发时所执行的方法
     */
    public void execute(JobExecutionContext context) throws JobExecutionException {
        userService.test();
        System.out.println("任务调度"+new Date());
    }
}

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

Caused by: java.lang.NullPointerException: null
    at 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容器中,并且完成该对象的属性注入
    @Autowired
    private AutowireCapableBeanFactory autowireCapableBeanFactory;

    /**
     * 该方法需要将实例化的 job 对象手动添加到SpringIOC 容器中并且完成实例化;
     */
    @Override
    public 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();
    //关联 Trigger
    schedulerFactoryBean.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.mfbz.cn/a/207918.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

对于Web标准以及W3C的理解、对viewport的理解、xhtml和html有什么区别?

1、对于Web标准以及W3C的理解 Web标准 Web标准简单来说可以分为结构、表现、行为。 其中结构是由HTML各种标签组成&#xff0c;简单来说就是body里面写入标签是为了页面的结构。 表现指的是CSS层叠样式表&#xff0c;通过CSS可以让我们的页面结构标签更具美感。 行为指的是…

2023年12月02日新闻简报(国内国际)

新闻简报 每天三分钟&#xff0c;朝闻天下事。今天是&#xff1a;2023年12月02日&#xff0c;星期六&#xff0c;农历十月廿十&#xff0c;祝工作愉快&#xff0c;身体健康&#xff0c;生活喜乐&#xff1a;&#xff1a; 国内新闻 1、商务部&#xff1a;对原产于澳大利亚的进…

【C指针】深入理解指针(最终篇)数组指针指针运算题解析(一)

&#x1f308;write in front :&#x1f50d;个人主页 &#xff1a; 啊森要自信的主页 ✏️真正相信奇迹的家伙&#xff0c;本身和奇迹一样了不起啊&#xff01; 欢迎大家关注&#x1f50d;点赞&#x1f44d;收藏⭐️留言&#x1f4dd;>希望看完我的文章对你有小小的帮助&am…

电商营销场景的RocketMQ实战01-RocketMQ原理

架构图 Broker主从架构与集群模式 RocketMQ原理深入剖析 Broker主从架构原理 HAConnection与HAClient Broker基于raft协议的主从架构 Consumer运行原理 基础知识 001_RocketMQ架构设计与运行流程分析 RocketMQ这一块&#xff0c;非常关键的一个重要的技术&#xff0c;面试的时候…

【Vue3+Ts项目】硅谷甄选 — 搭建后台管理系统模板

一、 项目初始化 一个项目要有统一的规范&#xff0c;需要使用eslintstylelintprettier来对我们的代码质量做检测和修复&#xff0c;需要使用husky来做commit拦截&#xff0c;需要使用commitlint来统一提交规范&#xff08;即统一提交信息&#xff09;&#xff0c;需要使用pre…

Day04:每日一题:2661. 找出叠涂元素

2661. 找出叠涂元素 给你一个下标从 0 开始的整数数组 arr 和一个 m x n 的整数 矩阵 mat 。 arr 和 mat 都包含范围 [1&#xff0c;m * n] 内的 所有 整数。从下标 0 开始遍历 arr 中的每个下标 i &#xff0c;并将包含整数 arr[i] 的 mat 单元格涂色。请你找出 arr 中在 mat…

ubuntu系统下搭建本地物联网mqtt服务器的步骤

那么假如我们需要做一些终端设备&#xff0c;例如温湿度传感器、光照等物联网采集设备要接入呢&#xff1f;怎么样才能将数据报送到服务器呢&#xff1f; 以下内容基于我们ubuntu系统下的emqx成功启动的基础上。我们可以用浏览器键入控制板的地址&#xff0c;如果启动成功&…

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

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

机器人仿真系统调研

仿真是机器人学习和研究过程中最重要的工具之一&#xff0c;是指通过计算机对实际的物理系统进行模拟的技术。机器人仿真基于交互式计算机图形技术和机器人学理论&#xff0c;生成机器人的几何图形&#xff0c;并对其进行三维显示&#xff0c;用来描述机器人及工作环境的动态变…

九章量子计算机:探索量子世界的革命性工具

九章量子计算机:探索量子世界的革命性工具 一、引言 九章量子计算机的推出,是近年来科技界最为引人瞩目的成就之一。这款基于量子力学的计算机,以其独特的计算方式和潜在的应用前景,引发了全球范围内的关注和讨论。本文将深入探讨九章量子计算机的原理、技术特点、应用前景…

计算机硬件(二)

1.内存和内存条的用途 假设运行内存16个g,能开多少软件 后台和前台能同时运行多少APP RAM越大越好 464 6128 8128 10256 例子: 8gx216g 两根内存条 16g运行内存 2.内存频率的用途 DDR5 DDR4 DDR3 后面的数字越大,越好,可以理解为传输的速度&#xff0c;内存搭配主…

小米智能摄像头mp4多碎片手工恢复案例

小米智能摄像头mp4多碎片手工恢复案例 智能摄像头目前在市场上极为常见&#xff0c;仅需要一张存储卡即可实现视频、音频的采集&#xff0c;同时可以通过手机APP进行远程控制&#xff0c;相比传统安防品牌成本更低、更容易部署。在智能摄像头品牌中小米算是绝对的大厂&#xf…

ES-深入理解倒排索引

倒排索引 idproductdesc1新版 小米 至尊-纪念版手机1小米 NFC 手机3NFC手机4小米 耳机5华为 耳机6扫地机器人7华为 Mata………………term_indexterm dictionaryposting list------------------------------------小米1……100W华为6,7,9NFC76,90耳机5352红米643,98机器人645,9…

数字电源为什么一般用DSP控制,而不能用普通的单片机?

数字电源为什么一般用DSP控制&#xff0c;而不能用普通的单片机&#xff1f; 首先你要清楚&#xff0c;数字电源需要一个芯片具备什么功能&#xff1f; 1 能发PWM波 &#xff0c;并且具备保护关断功能&#xff1b; 电源对PWM发波 要求很高&#xff0c;精度要ns级甚至ps级的&…

C++中异常的栈展开概念

C中的异常栈展开是指&#xff0c;当某个函数中有异常产生&#xff08;这里不考虑是主动抛出的还是被动产生的&#xff09;&#xff0c;在异常被捕获之前的函数调用链上&#xff0c;函数不会正常执行返回&#xff0c;即异常产生之后的程序逻辑不会被执行。 &#xff08;注意&…

RTDETR阅读笔记

RTDETR阅读笔记 摘要 DETR的高计算成本限制了它们的实际应用&#xff0c;并阻碍了它们充分利用无需后处理&#xff08;例如非最大抑制NMS&#xff09;的优势。文中首先分析了NMS对实施目标检测的精度和速度的负面影响。&#xff08;RTDETR是第一个实时端到端的目标检测器。具…

temu货不对板哪里修改图片

在Temu这个跨境电商平台上&#xff0c;如果您需要修改商品图片&#xff0c;通常需要在卖家中心进行操作。下面是一般的步骤&#xff0c;但请注意&#xff0c;不同平台的操作可能略有不同&#xff0c;具体请参考Temu官方的帮助文档或联系客服。 先给大家推荐一款拼多多/temu运营…

OpenCV快速入门:彩蛋——小游戏制作

文章目录 前言一、游戏玩法1.1 核心玩法1.2 特殊事件 二、功能模块划分2.1 主游戏文件 (main.py)2.2 游戏对象 (game_objects.py)2.3 游戏逻辑 (game_logic.py)2.4 事件和奖励 (events_and_rewards.py)2.5. 游戏界面 (game_ui.py) 三、完整代码3.1 主游戏文件 (main.py)3.1.1 游…

计算机网络(超详解!) 第二节 物理层(下)

1.信道复用技术 复用 (multiplexing) 是通信技术中的基本概念。 它允许用户使用一个共享信道进行通信&#xff0c;降低成本&#xff0c;提高利用率。 1.频分复用 FDM(Frequency Division Multiplexing) 将整个带宽分为多份&#xff0c;用户在分配到一定的频带后&#xff0c;…

20、LED点阵屏

LED点阵屏介绍 LED点阵屏由若干个独立的LED组成&#xff0c;LED以矩阵的形式排列&#xff0c;以灯珠亮灭来显示文字、图片、视频等。LED点阵屏广泛应用于各种公共场合&#xff0c;如汽车报站器、广告屏以及公告牌等 LED点阵屏分类 按颜色&#xff1a;单色、双色、全彩 按像素…
最新文章