Spring定时任务--手动执行定时任务(替代@Scheduled)

news2025/1/15 22:42:56

原文网址:Spring定时任务--手动执行定时任务(替代@Scheduled)

简介

本文介绍SpringBoot如何手动执行定时任务。

之前此文已经介绍过,直接用@Scheduled即可使用Spring的定时任务,但有时需要手动去提交定时任务,比如:

  1. 从其他位置获取cron配置,无法写到注解。
  2. 有不确定个数的任务,不能在代码中写死。

方案1:实现 SchedulingConfigurer 接口

本处从数据库读取配置,然后提交定时任务。

创建定时器

编写定时任务,这里添加的是TriggerTask,循环读取我们在数据库设置好的执行周期,以及执行相关定时任务的内容。

@Configuration
@EnableScheduling
public class DynamicScheduleTask implements SchedulingConfigurer {
    @Autowired
    private CronMapper cronMapper;
    
    /**
     * 执行定时任务.
     */
    @Override
    public void configureTasks(ScheduledTaskRegistrar taskRegistrar) {

        taskRegistrar.addTriggerTask(
                //1.添加任务内容(Runnable)
                () -> System.out.println("执行动态定时任务: " + LocalDateTime.now().toLocalTime()),

                //2.设置执行周期(Trigger)
                triggerContext -> {
                    //2.1 从数据库获取执行周期
                    String cron = cronMapper.getCron();
                    //2.2 合法性校验.
                    if (StringUtils.isEmpty(cron)) {
                        // Omitted Code ..
                    }
                    //2.3 返回执行周期(Date)
                    return new CronTrigger(cron).nextExecutionTime(triggerContext);
                }
        );
    }

}

表结构与数据

开启本地数据库mysql,随便打开查询窗口,然后执行脚本内容,如下

DROP DATABASE IF EXISTS `socks`;
CREATE DATABASE `socks`;
USE `SOCKS`;
DROP TABLE IF EXISTS `cron`;
CREATE TABLE `cron`  (
  `cron_id` varchar(30) NOT NULL PRIMARY KEY,
  `cron` varchar(30) NOT NULL  
);
INSERT INTO `cron` VALUES ('1', '0/5 * * * * ?');

项目中的application.yml 添加数据源

spring:
  datasource:
    url: jdbc:mysql://localhost:3306/socks
    username: root
    password: 123456

启动测试

启动应用后,查看控制台,打印时间是我们预期的每10秒一次:

打开Navicat ,将执行周期修改为每6秒执行一次,如图

如果在数据库修改时格式出现错误,则定时任务会停止,即使重新修改正确;此时只能重新启动项目才能恢复。

方案2:ThreadPoolTaskScheduler

上边的实例的定时任务在SprinBoot在启动时就启动,也可以在代码中任意启动/关闭/调整时间。如下:

package com.example.demo.task;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler;
import org.springframework.scheduling.support.CronTrigger;
import org.springframework.stereotype.Component;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.Date;
import java.util.concurrent.ScheduledFuture;

@RestController
@Component
public class TestScheduler {
    @Autowired
    private ThreadPoolTaskScheduler threadPoolTaskScheduler;

    private ScheduledFuture<?> future;

    @Bean
    public ThreadPoolTaskScheduler threadPoolTaskScheduler() {
        return new ThreadPoolTaskScheduler();
    }

    @RequestMapping("/startCron")
    public String startCron() {

        future = threadPoolTaskScheduler.schedule(new MyRunnable(), new CronTrigger("0/5 * * * * *"));
        System.out.println("DynamicTask.startCron()");
        return "startCron";
    }

    @RequestMapping("/stopCron")
    public String stopCron() {

        if (future != null) {
            future.cancel(true);
        }
        System.out.println("DynamicTask.stopCron()");
        return "stopCron";
    }

    @RequestMapping("/changeCron10")
    public String startCron10() {

        stopCron();// 先停止,在开启.
        future = threadPoolTaskScheduler.schedule(new MyRunnable(), new CronTrigger("*/10 * * * * *"));
        System.out.println("DynamicTask.startCron10()");
        return "changeCron10";
    }

    private class MyRunnable implements Runnable {

        @Override
        public void run() {
            System.out.println("DynamicTask.MyRunnable.run()," + new Date());
        }
    }
}

浏览器分别输入:http://localhost:8080/startCron、http://localhost:8080/stopCron 

执行结果

  .   ____          _            __ _ _
 /\\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
 \\/  ___)| |_)| | | | | || (_| |  ) ) ) )
  '  |____| .__|_| |_|_| |_\__, | / / / /
 =========|_|==============|___/=/_/_/_/
 :: Spring Boot ::        (v2.3.0.RELEASE)

2020-05-27 19:48:02.370  INFO 6804 --- [           main] com.example.demo.DemoApplication         : Starting DemoApplication on liu-PC with PID 6804 (E:\work\idea_proj\test-SpringBoot\target\classes started by liu in E:\work\idea_proj\test-SpringBoot)
2020-05-27 19:48:02.373  INFO 6804 --- [           main] com.example.demo.DemoApplication         : No active profile set, falling back to default profiles: default
2020-05-27 19:48:03.675  INFO 6804 --- [           main] o.s.b.w.embedded.tomcat.TomcatWebServer  : Tomcat initialized with port(s): 8080 (http)
2020-05-27 19:48:03.684  INFO 6804 --- [           main] o.apache.catalina.core.StandardService   : Starting service [Tomcat]
2020-05-27 19:48:03.684  INFO 6804 --- [           main] org.apache.catalina.core.StandardEngine  : Starting Servlet engine: [Apache Tomcat/9.0.35]
2020-05-27 19:48:03.941  INFO 6804 --- [           main] o.a.c.c.C.[Tomcat].[localhost].[/]       : Initializing Spring embedded WebApplicationContext
2020-05-27 19:48:03.941  INFO 6804 --- [           main] o.s.web.context.ContextLoader            : Root WebApplicationContext: initialization completed in 1523 ms
2020-05-27 19:48:04.001  INFO 6804 --- [           main] o.s.s.c.ThreadPoolTaskScheduler          : Initializing ExecutorService 'threadPoolTaskScheduler'
2020-05-27 19:48:04.405  INFO 6804 --- [           main] o.s.b.w.embedded.tomcat.TomcatWebServer  : Tomcat started on port(s): 8080 (http) with context path ''
2020-05-27 19:48:04.419  INFO 6804 --- [           main] com.example.demo.DemoApplication         : Started DemoApplication in 3.328 seconds (JVM running for 8.111)
2020-05-27 19:48:39.380  INFO 6804 --- [nio-8080-exec-1] o.a.c.c.C.[Tomcat].[localhost].[/]       : Initializing Spring DispatcherServlet 'dispatcherServlet'
2020-05-27 19:48:39.380  INFO 6804 --- [nio-8080-exec-1] o.s.web.servlet.DispatcherServlet        : Initializing Servlet 'dispatcherServlet'
2020-05-27 19:48:39.405  INFO 6804 --- [nio-8080-exec-1] o.s.web.servlet.DispatcherServlet        : Completed initialization in 25 ms
DynamicTask.startCron()
DynamicTask.MyRunnable.run(),Wed May 27 19:48:50 CST 2020
DynamicTask.MyRunnable.run(),Wed May 27 19:48:55 CST 2020
DynamicTask.MyRunnable.run(),Wed May 27 19:49:00 CST 2020
DynamicTask.MyRunnable.run(),Wed May 27 19:49:05 CST 2020
DynamicTask.MyRunnable.run(),Wed May 27 19:49:10 CST 2020
DynamicTask.stopCron()

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

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

相关文章

phtread_cancel函数用于取消线程,但不是实时的

如上图所示&#xff0c;线程函数中没有取消点&#xff08;一般是一些系统调用----man 7 pthreads查看&#xff0c;自定义函数是无效的&#xff09;&#xff0c;则使用pthread_cancle函数不生效。 解决方法&#xff1a;可以添加pthread_testcancle(); 通过pthread_join回收的…

【QT+QGIS跨平台编译】之五十一:【QGIS_CORE跨平台编译】—【qgsexpressionparser.cpp生成】

文章目录 一、Bison二、生成来源三、构建过程一、Bison GNU Bison 是一个通用的解析器生成器,它可以将注释的无上下文语法转换为使用 LALR (1) 解析表的确定性 LR 或广义 LR (GLR) 解析器。Bison 还可以生成 IELR (1) 或规范 LR (1) 解析表。一旦您熟练使用 Bison,您可以使用…

37、IO进程线程/使用消息队列完成进程间通信20240225

一、使用消息队列完成两个进程间相互通信。 代码&#xff1a; 进程1代码&#xff1a; #include<myhead.h> struct msgbuf {long mtype;//消息类型char mtext[1024];//消息正文 }; //宏定义结构体消息正文大小 #define MSGSIZE (sizeof(struct msgbuf)-sizeof(long)) i…

微信小程序(四十五)登入界面-简易版

注释很详细&#xff0c;直接上代码 上一篇 此文使用了vant组件库&#xff0c;没有安装配置的可以参考此篇vant组件的安装与配置 新增内容&#xff1a; 1.基础组件的组合 2.验证码倒计时的逻辑处理 源码&#xff1a; app.json {"usingComponents": {"van-field…

RabbitMQ快速入门笔记

学习视频参考 3.RabbitMQ的安装(二)_哔哩哔哩_bilibili 06-MQ的分类_哔哩哔哩_bilibili RabbitMQ官网 RabbitMQ: easy to use, flexible messaging and streaming | RabbitMQ 目录 1.MQ引言 1.1 什么是MQ&#xff1f; 1.2 MQ的分类 1.2.1 ActivaMQ 1.2.2 Kafka 1.2.3 R…

挑战杯 基于机器学习与大数据的糖尿病预测

文章目录 1 前言1 课题背景2 数据导入处理3 数据可视化分析4 特征选择4.1 通过相关性进行筛选4.2 多重共线性4.3 RFE&#xff08;递归特征消除法&#xff09;4.4 正则化 5 机器学习模型建立与评价5.1 评价方式的选择5.2 模型的建立与评价5.3 模型参数调优5.4 将调参过后的模型重…

Unity3D 使用 Proto

一. 下载与安装 这里下载Google Protobuff下载 1. 源码用来编译CSharp 相关配置 2. win64 用于编译 proto 文件 二. 编译 1. 使用VS 打开 2. 点击最上面菜单栏 工具>NuGet 包管理器>管理解决方案的NuGet 管理包 版本一定要选择咱们一开始下载的对应版本否则不兼容&am…

WPF 【十月的寒流】学习笔记(1):DataGrid过滤

文章目录 相关链接代码仓库前言环境DataGrid 数据筛选项目配置使用原理主要代码&#xff08;详细代码可以看我的GitHub仓库&#xff09;Models.PersonDataGirdViewDataGridViewModel 实现效果 总结 相关链接 十月的寒流 在 WPF 中制作 DataGrid 的数据筛选功能 WPF 中如何制作 …

计算机网络面经-TCP的拥塞控制

写在前边 前边我们分享了网络分层协议、TCP 三次握手、TCP 四次分手。今天我们继续深入分享一下 TCP 中的拥塞控制。 对于 TCP 的拥塞控制,里边设计到很多细节,平平无奇的羊希望通过这一节能够将这部分内容串通起来,能够让你更深刻的记忆这部分内容。 思维导图 1、什么…

前端工程化面试题 | 18.精选前端工程化高频面试题

&#x1f90d; 前端开发工程师、技术日更博主、已过CET6 &#x1f368; 阿珊和她的猫_CSDN博客专家、23年度博客之星前端领域TOP1 &#x1f560; 牛客高级专题作者、打造专栏《前端面试必备》 、《2024面试高频手撕题》 &#x1f35a; 蓝桥云课签约作者、上架课程《Vue.js 和 E…

智慧校园|智慧校园管理小程序|基于微信小程序的智慧校园管理系统设计与实现(源码+数据库+文档)

智慧校园管理小程序目录 目录 基于微信小程序的智慧校园管理系统设计与实现 一、前言 二、系统功能设计 三、系统实现 1、微信小程序前台 2、管理员后台 &#xff08;1&#xff09;学生信息管理 &#xff08;2&#xff09; 作业信息管理 &#xff08;3&#xff09;公告…

考研408深度分析+全年规划

408确实很难&#xff0c;他的难分两方面 一方面是408本身的复习难度&#xff0c;我们都知道&#xff0c;408的考察科目有四科&#xff0c;分别是数据结构&#xff0c;计算机组成原理&#xff0c;操作系统和计算机网络。大家回想一下自己在大学本科时候学习这些专业课的难度&am…

electron+vue3全家桶+vite项目搭建【27】封装窗口工具类【1】雏形

文章目录 引入思路抽出公共声明文件抽出全局通用数据类型和方法主进程模块1.抽离基础常量2.封装窗口工具类 渲染进程模块测试结果 引入 demo项目地址 可以看到我们之前在主进程中的逻辑全部都塞到index.ts文件中&#xff0c;包括窗口的一些事件处理&#xff0c;handle监听&am…

OPENSSL-PKCS7入门知识介绍

1 PKCS7数据结构说明 p7包括6种数据内容&#xff1a;数据(data),签名数据&#xff08;sign&#xff09;&#xff0c;数字信封数据&#xff08;enveloped&#xff09;&#xff0c;签名数字信封数据&#xff08;signed_and_enveloped&#xff09;&#xff0c;摘要数据&#xff08…

中海油、中石化、中石油校招历年真题和题库

中海油、中石化、中石油是中国领先的石油和天然气公司&#xff0c;拥有雄厚的实力和丰富的资源&#xff0c;是许多求职者梦寐以求的就业机会。为了帮助应聘者更好地备战这三家公司的校园招聘&#xff0c;我特别整理了三套精心准备的校招试题资料&#xff0c;涵盖了各个领域的知…

ARM Cortex-X5 传言表现不佳,高功率浪涌和低多核分数影响即将推出的核心设计

ARM 的新 Cortex-X5 设计似乎遇到了问题&#xff0c;有新的传言称&#xff0c;超级核心在提高时钟速度时会经历严重的高功耗&#xff0c;并且当最大功率限制降低时&#xff0c;多核性能会下降。虽然这对高通来说可能不是问题&#xff0c;因为据说其 Snapdragon 8 Gen 4 采用定制…

uni-app vue3 setup nvue中webview层级覆盖问题

核心就是这两行&#xff0c;&#x1f923;发现设置后不能点击了&#xff0c;这个玩意可能只能弹窗打开的时候动态的修改 position: static, zindex: 0onLoad(options > {loadWebview()})function loadWebview() {let pageInfo uni.getSystemInfoSync();width.value pageI…

静态时序分析:SDC约束命令set_load详解

相关阅读 静态时序分析https://blog.csdn.net/weixin_45791458/category_12567571.html?spm1001.2014.3001.5482 set_load命令用于指定端口(port)或线网(net)的负载电容&#xff0c;该指令的BNF范式&#xff08;有关BNF范式&#xff0c;可以参考以往文章&#xff09;为&#…

Kafka之Consumer源码

Consumer源码解读 Consumer初始化 从KafkaConsumer的构造方法出发&#xff0c;我们跟踪到核心实现方法 这个方法的前面代码部分都是一些配置&#xff0c;我们分析源码要抓核心&#xff0c;我把核心代码给摘出来 NetworkClient Consumer与Broker的核心通讯组件 ConsumerCoord…

【数据结构】周末作业

1.new(struct list_head*)malloc(sizeof(struct list_head*)); if(newNULL) { printf("失败\n"); return; } new->nextprev->next; prev->nextnew; return; 2.struct list_head* pprev->next; prev->nextp->next; p->next->prevpr…