如何把Java的定时任务写到数据库里面去配置?

之前是这样写的,每次要改定时器都要修改发版,很麻烦:

package cn.net.cdsz.ccb.common.scheduled;

import cn.net.cdsz.ccb.business.config.Custom;
import cn.net.cdsz.ccb.business.service.CCBBankService;
import cn.net.cdsz.ccb.business.service.CCBTestSetService;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;

/**
 * 这个是每6小时(程序启动)执行一次的   
 */
@Component
@EnableAsync
public class correctMoney {
    @Autowired
    private Custom custom  ;

    private Logger logger = LogManager.getLogger();

    @Autowired
    private CCBTestSetService cCBTestSetService;

    //@Scheduled(fixedRate = 60000)   // 60000每隔一分钟执行一次
    @Scheduled(cron = " 0 0 0 * * ?") // 每天凌晨执行一次 ,专业  [秒] [分] [小时] [日] [月] [周] [年]
    //@Scheduled(cron = " 0 * * * * ?")//这样是每3秒执行一次了,专业  [秒] [分] [小时] [日] [月] [周] [年]
    public void run() {

        if(custom.getIsscheduled()){

            try {
                run(()-> {
                   cCBTestSetService.AutomaticDeductionByDay(); 
                });
            }catch (RuntimeException e){
                logger.error(e.getMessage());
            }catch (Exception e){
                logger.error(e);
            }

        }

    }

    public void run(Runnable runnable) {
        runnable.run();
    }

}

现在改成数据库里面去配置定时器了,就容易了很多,上代码:

package cn.net.cdsz.ccb.common.scheduled;

import club.newepoch.utils.JsonUtils;
import club.newepoch.utils.StringUtils;
import cn.net.cdsz.ccb.business.model.pojo.ScheduledTask;
import cn.net.cdsz.ccb.business.model.pojo.ScheduledTaskLog;
import cn.net.cdsz.ccb.common.bean.BaseHolder;
import cn.net.cdsz.ccb.common.event.GenTables;
import lombok.SneakyThrows;
import org.springframework.scheduling.TaskScheduler;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.scheduling.support.CronTrigger;
import org.springframework.stereotype.Service;
import java.lang.reflect.Method;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ScheduledFuture;

/**
 * 动态调度器(配置写数据库)
 */
@Service
public class DynamicScheduler {
    final private TaskScheduler taskScheduler;
    final private  GenTables genTables;
    private Map<Long, ScheduledFuture<?>> jobsMap = new ConcurrentHashMap<>();
    private Map<Long, String> taskCronMap = new ConcurrentHashMap<>();//自己维护一个调度时间的表
    public DynamicScheduler(TaskScheduler taskScheduler, GenTables genTables) {
        this.genTables = genTables;
        this.taskScheduler = taskScheduler;
    }

    // 这个方法用来启动所有的active任务
    //@PostConstruct
    public void startActiveJobs() {
        ScheduledTask scheduledTaskSql = new ScheduledTask();
        List<ScheduledTask> tasks = genTables.queryMore(scheduledTaskSql);
        tasks.forEach(this::scheduleTask);
    }

    // 用于调度任务
    public void scheduleTask(ScheduledTask task) {
        if ("1".equals(task.getIsActive())) {
            ScheduledFuture<?> scheduledTask = taskScheduler.schedule(
                    () -> runTask(task),
                    new CronTrigger(task.getCronExpression(), TimeZone.getTimeZone(TimeZone.getDefault().getID()))
            );
            jobsMap.put(task.getKeyId(), scheduledTask);
            taskCronMap.put(task.getKeyId(), task.getCronExpression());
        } else {
            cancelTask(task.getKeyId());
        }
    }

    // 用于取消计划中的任务
    public void cancelTask(Long taskId) {
        ScheduledFuture<?> scheduledTask = jobsMap.get(taskId);
        if (scheduledTask != null) {
            scheduledTask.cancel(true);
            jobsMap.remove(taskId);
            taskCronMap.remove(taskId);
        }
    }
    @SneakyThrows
    // 调用转换函数,将字符串值转换为对应的对象类型
    private Object convertStringToObject(String value, Class<?> type) {
        if (String.class == type) {
            return value;
        } else if (Integer.class == type || int.class == type) {
            return Integer.valueOf(value);
        } else if (Double.class == type || double.class == type) {
            return Double.valueOf(value);
        }
        // 可以根据需要添加更多类型的转换
        throw new IllegalArgumentException("Unsupported type: " + type);
    }

    private void runTask(ScheduledTask task) {
        // 这里执行你的任务逻辑9 15
        Object bean = BaseHolder.getBean(task.getBeanStr());    // 获取bean实例
        String methodName = task.getExecMath();          // 从数据库获取的方法名
        String paramTypeNamesStr = task.getParamTypeNamesStr(); // 从数据库获取的参数类型名字符串
        String paramValuesStr = task.getParamValuesStr();    // 从数据库获取的参数值字符串
        // 使用.split(", ")方法来分割字符串并转换为数组,然后将数组转换为列表
        List<String> paramTypeNames = Arrays.asList(paramTypeNamesStr.split(","));  // 方法参数类型
        List<String> paramValues = Arrays.asList(paramValuesStr.split(","));// 方法参数值

        // 将字符串类型名称转换为Class类型对象
        Class<?>[] parameterTypes = new Class<?>[paramTypeNames.size()];
        for (int i = 0; i < paramTypeNames.size(); i++) {
            try {
                if(StringUtils.isBlank(paramTypeNames.get(i))){
                    continue;
                }
                parameterTypes[i] = Class.forName(paramTypeNames.get(i));
            } catch (ClassNotFoundException e) {
                throw new RuntimeException(e);
            }
        }

        // 将字符串参数值转换为相应的对象
        Object[] parameters = new Object[paramValues.size()];
        for (int i = 0; i < paramValues.size(); i++) {
            if(StringUtils.isBlank(paramValues.get(i))){
                continue;
            }
            String value = paramValues.get(i);
            Class<?> type = parameterTypes[i];
            // 调用转换函数,将字符串值转换为对应的对象类型
            parameters[i] = convertStringToObject(value, type);
        }
        // 写日志。。。
        ScheduledTaskLog  scheduledTaskLog = new ScheduledTaskLog();
        scheduledTaskLog.setTaskName(task.getTaskName());
        scheduledTaskLog.setCronExpression(task.getCronExpression());
        scheduledTaskLog.setBeanStr(task.getBeanStr());
        scheduledTaskLog.setExecMath(task.getExecMath());
        scheduledTaskLog.setParamTypeNamesStr(task.getParamTypeNamesStr());
        scheduledTaskLog.setParamValuesStr(task.getParamValuesStr());
        // ... 接下来是通过反射调用方法的过程 ...
        try {
            Method method;
            // 判断是否有参数类型存在
            if ((parameterTypes == null || parameterTypes.length == 0) || (parameters == null || Arrays.stream(parameters).allMatch(Objects::isNull))) {
                // 如果没有参数类型则认为是不带参数的方法
                method = bean.getClass().getMethod(methodName);
                // 使用.invoke()调用方法,传入bean和参数数组
                Object result = method.invoke(bean);
                scheduledTaskLog.setResultStr(JsonUtils.toJSONString(result));
            } else {
                // 获取具有指定参数类型的方法对象
                method = bean.getClass().getMethod(methodName, parameterTypes);
                // 使用.invoke()调用方法,传入bean和参数数组
                Object result = method.invoke(bean, parameters);
                scheduledTaskLog.setResultStr(JsonUtils.toJSONString(result));
            }
            //保存调度的执行日志
            genTables.save(scheduledTaskLog);
            // 处理调用结果
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
            // 处理没有找到具有指定参数类型的方法的情况
        } catch (Exception e) {
            e.printStackTrace();
            // 处理其他可能的异常
        }
    }

    // 你可以通过定时任务,周期性地从数据库中获取最新的任务配置
    @Scheduled(fixedRate = 1000*60) //单位是毫秒(ms)
    public void refreshActiveJobs() {
        // 查询数据库中所有active的任务并更新调度
        ScheduledTask scheduledTaskSql = new ScheduledTask();
        List<ScheduledTask> tasks = genTables.queryMore(scheduledTaskSql);

        for (int i = 0; i < tasks.size(); i++) {
            ScheduledTask task = tasks.get(i);
            if (!jobsMap.containsKey(task.getKeyId())) {
                // 如果在内存中不存在,则为新任务,需要调度
                scheduleTask(task);
            } else {
                // 如果已经存在,检查cron表达式是否更新
                String cronStr = taskCronMap.get(task.getKeyId());
                // 如果内容不一样,那么就修改这个计划
                if(!cronStr.equals(task.getCronExpression())){
                    // Cron表达式已更改,重新调度
                    cancelTask(task.getKeyId());
                    scheduleTask(task);
                }
            }
        }
        // 取消已经被设置为非active的任务
        for (Map.Entry<Long, ScheduledFuture<?>> entry : jobsMap.entrySet()) {
            Long taskId = entry.getKey();
            ScheduledTask scheduledTaskSql2 = new ScheduledTask();
            scheduledTaskSql2.setKeyId(taskId);
            ScheduledTask scheduledTask = genTables.queryOne(scheduledTaskSql2);
            if (scheduledTask !=null && "0".equals(scheduledTask.getIsActive())) {
                cancelTask(taskId);
            }
        }

    }
}

上一个线程的辅助类:

    package cn.net.cdsz.ccb.common.config.app;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.TaskScheduler;
import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler;

@Configuration
public class AppConfig {
    @Bean
    public TaskScheduler taskScheduler() {
        ThreadPoolTaskScheduler scheduler = new ThreadPoolTaskScheduler();
        // 设定线程池大小,可以根据实际情况调整
        scheduler.setPoolSize(5);
        // 设置线程名称前缀
        scheduler.setThreadNamePrefix("TaskScheduler-");
        // 线程池关闭前的最大等待时间,确保所有任务都能完成
        scheduler.setAwaitTerminationSeconds(600);
        // 设置当调度器shutdown被调用时等待当前被调度的任务完成
        scheduler.setWaitForTasksToCompleteOnShutdown(true);
        // 初始化线程池
        scheduler.initialize();
        return scheduler;
    }
}

上数据库表的sql:

CREATE TABLE `scheduled_task` (
  `key_id` bigint(19) NOT NULL AUTO_INCREMENT,
  `task_name` varchar(255) NOT NULL DEFAULT '' COMMENT '任务名字',
  `cron_expression` varchar(255) NOT NULL DEFAULT '' COMMENT '周期配置比如:0 30 0 * * ?',
  `is_active` tinyint(4) NOT NULL DEFAULT '1' COMMENT '是否有效',
  `bean_str` varchar(255) NOT NULL DEFAULT '' COMMENT '获取bean实例',
  `exec_math` varchar(255) NOT NULL DEFAULT '' COMMENT '从数据库获取的方法名,写一个',
  `param_type_names_str` varchar(255) NOT NULL DEFAULT '' COMMENT '从数据库获取的参数类型名字符串,用英文,隔开',
  `param_values_str` varchar(255) NOT NULL DEFAULT '' COMMENT '从数据库获取的参数值字符串,用英文,隔开',
  `add_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
  `modify_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
  `lived` tinyint(4) NOT NULL DEFAULT '0',
  PRIMARY KEY (`key_id`)
) ENGINE=InnoDB AUTO_INCREMENT=6 DEFAULT CHARSET=utf8mb4 ROW_FORMAT=DYNAMIC COMMENT='动态调度(手动配置的定时器)';




CREATE TABLE `scheduled_task_log` (
  `key_id` bigint(19) NOT NULL AUTO_INCREMENT,
  `task_name` varchar(255) NOT NULL DEFAULT '',
  `cron_expression` varchar(255) NOT NULL DEFAULT '',
  `bean_str` varchar(255) NOT NULL DEFAULT '',
  `exec_math` varchar(255) NOT NULL DEFAULT '',
  `param_type_names_str` varchar(255) NOT NULL DEFAULT '',
  `param_values_str` varchar(255) NOT NULL DEFAULT '',
  `result_str` text,
  `add_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
  `modify_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
  `lived` tinyint(4) NOT NULL DEFAULT '0',
  PRIMARY KEY (`key_id`)
) ENGINE=InnoDB AUTO_INCREMENT=36625 DEFAULT CHARSET=utf8mb4 ROW_FORMAT=DYNAMIC;

上截图:

注意:把这个加上,固定好类在spring容器中的类名,要和数据库中的数据保存一致!

完毕!

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

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

相关文章

机器学习项目实践-基础知识部分

环境建立 我们做项目第一步就是单独创建一个python环境&#xff0c;Python新的隔离环境 创建&#xff1a;python -m venv ml 使用&#xff1a;.\Scripts\activate python -m venv ml 是在创建一个名为 ml 的虚拟环境&#xff0c;这样系统会自动创建一个文件夹ml&#xff0c;…

做题速度太慢了,面不上

没办法&#xff0c;之前练了一个月的sql。两个月不写&#xff0c;现在差不多忘干净了。工作空窗期&#xff0c;或者休息期不能太久&#xff0c;不然学再多的内容都可能会忘完的。 sql题&#xff0c;腾讯四道sql题&#xff0c;限时45分钟完成。我只做了一道&#xff0c;还没做完…

重磅!结合AI、高光谱与GEE的双碳目标智能监测与模拟前沿

以全球变暖为主要特征的气候变化已成为全球性环境问题&#xff0c;对全球可持续发展带来严峻挑战。2015年多国在《巴黎协定》上明确提出缔约方应尽快实现碳达峰和碳中和目标。2019年第49届 IPCC全会明确增加了基于卫星遥感的排放清单校验方法。随着碳中和目标以及全球碳盘点的现…

RabbitMQ的介绍和使用

1.同步通讯和异步通讯 举个例子&#xff0c;同步通讯就像是在打电话&#xff0c;因此它时效性较强&#xff0c;可以立即得到结果&#xff0c;但如果你正在和一个MM打电话&#xff0c;其他MM找你的话&#xff0c;你们之间是不能进行消息的传递和响应的 异步通讯就像是微信&#…

Linux系统使用Docker安装青龙面板并实现远程访问管理面板

文章目录 一、前期准备本教程环境为&#xff1a;Centos7&#xff0c;可以跑Docker的系统都可以使用。本教程使用Docker部署青龙&#xff0c;如何安装Docker详见&#xff1a; 二、安装青龙面板三、映射本地部署的青龙面板至公网四、使用固定公网地址访问本地部署的青龙面板 青龙…

【busybox记录】【shell指令】shuf

目录 内容来源&#xff1a; 【GUN】【shuf】指令介绍 【busybox】【shuf】指令介绍 【linux】【shuf】指令介绍 使用示例&#xff1a; 打乱内容 - 默认输出 打乱内容 - 最多输出n行 打乱内容 - 将输出写入文件 打乱内容 - 重复输出 打乱内容 - 打乱本条指令的参数 打…

C语言 自定义类型——联合体

目录: 一、联合体是&#xff1f;声明计算内存大小 二、联合体的特点例如 三、联合体大小的计算规则&#xff1a; 四、应用习1习2 一、联合体是&#xff1f; 联合体和结构体差不多&#xff0c;但是其最大的区别在于联合体所有的成员共用一块内存空间。所以联合体也叫共用体。联…

方法的重写

方法的重写 概念&#xff1a;子类继承父类之后&#xff0c;就拥有了符合权限的父类的属性和方法&#xff0c;但是当父类的方法不符合子类的要求的时候&#xff0c;子类也可以重新的书写自己想要的方法。所以&#xff0c;方法的重写&#xff0c;即子类继承父类的方法后&#xf…

「代码与养生」 :当下程序员的养生指南

前言 众所周知&#xff0c;程序员是死的比较快的一类人。因为天天加班、睡眠不足、久坐不动、长时间面对电子屏幕辐射、长时间高强度用脑等不好避免的问题。因此&#xff0c;要想活的时间长一点&#xff0c;就要多了解一些养生之道 下面&#xff0c;根据个人看的一些博客、书…

深度学习之基于Matlab卷积神经网络验证码识别系统

欢迎大家点赞、收藏、关注、评论啦 &#xff0c;由于篇幅有限&#xff0c;只展示了部分核心代码。 文章目录 一项目简介 二、功能三、系统四. 总结 一项目简介 一、项目背景 随着互联网的发展&#xff0c;验证码作为一种常用的安全验证手段&#xff0c;被广泛应用于各种网站和…

网络安全--红队资源大合集

目录 相关资源列表 攻防测试手册 内网安全文档 学习靶场 工具包集合 内网安全文档 学习手册相关资源 产品设计文档 版本管理平台漏洞收集 相关工具拓展插件 Kali 环境下拓展插件 Nessus 相关工具拓展插件 Awvs 相关工具拓展插件 红队攻击的生命周期&#xff0c;…

基于FPGA的AD7705芯片驱动设计VHDL代码Quartus仿真

名称&#xff1a; 软件&#xff1a;Quartus基于FPGA的AD7705芯片驱动设计VHDL代码Quartus仿真&#xff08;文末获取&#xff09; 语言&#xff1a;VHDL 代码功能&#xff1a; AD77025芯片控制及串口输出 1、使用FPGA控制AD77025芯片&#xff0c;使其输出AD值 2、将数据计…

基于springboot实现夕阳红公寓管理系统项目【项目源码+论文说明】

基于springboot实现夕阳红公寓管理系统演示 摘要 如今社会上各行各业&#xff0c;都在用属于自己专用的软件来进行工作&#xff0c;互联网发展到这个时候&#xff0c;人们已经发现离不开了互联网。互联网的发展&#xff0c;离不开一些新的技术&#xff0c;而新技术的产生往往是…

ASP.NET网上鲜花销售系统的设计

摘 要 本系统实现了一般电子商务所具备的功能&#xff0c;如商品浏览、用户登录注册、网上与购物、结算、后台数据库管理等&#xff0c;利用这些功能可以对鲜花销售信息进行较好的管理。 网上鲜花销售系统的使用者主要是客户和销售管理者&#xff0c;对于客户来说&#xff0…

欧式聚类提取-------PCL

欧式聚类 std::vector<pcl::PointCloud<pcl::PointXYZ>::Ptr> PclTool::euclideanClustering(const pcl::PointCloud<pcl::PointXYZ>::Ptr& cloud) {std::vector<pcl::PointCloud<pcl::PointXYZ>::Ptr> clustered_clouds;// 下采样pcl::Vox…

基于FPGA的DDS波形发生器VHDL代码Quartus仿真

名称&#xff1a;基于FPGA的DDS波形发生器VHDL代码Quartus仿真&#xff08;文末获取&#xff09; 软件&#xff1a;Quartus 语言&#xff1a;VHDL 代码功能&#xff1a; DDS波形发生器VHDL 1、可以输出正弦波、方波、三角波 2、可以控制输出波形的频率 DDS波形发生器原理…

学习和分析各种数据结构所要掌握的一个重要知识——CPU的缓存利用率(命中率)

什么是CPU缓存利用率&#xff08;命中率&#xff09;&#xff0c;我们首先要把内存搞清楚。 硬盘是什么&#xff0c;内存是什么&#xff0c;高速缓存是什么&#xff0c;寄存器又是什么&#xff1f; 我们要储存数据就要运用到上面的东西。首先里面的硬盘是可以无电存储的&#…

无人零售,重塑购物新纪元

在这个快节奏的时代&#xff0c;科技的每一次跃进都在悄无声息地改变着我们的生活方式。而今&#xff0c;无人零售正以雷霆之势&#xff0c;颠覆传统购物模式&#xff0c;为我们带来前所未有的便捷与智能体验。想知道无人零售如何彻底改变我们的购物方式吗&#xff1f;跟随我&a…

Linux实现Flappy bird项目

目录 1、项目介绍 2、功能总结 3、前期准备 3.1 Ncurses库 3.2 信号机制 3.2.1 设置信号响应方式 3.2.2 设置定时器 4、代码实现 4.1 头文件引用及变量、函数定义 4.2 主函数 4.3 curses初始化 4.4 设置定时器 4.5 定时器响应函数 4.6 小鸟控制相关函数 4…

Java的Fork-Join简单介绍

Java的Fork-Join框架是Java 7引入的一个用于并行处理的轻量级框架&#xff0c;它基于分治策略&#xff08;Divide and Conquer&#xff09;&#xff0c;特别适合于那些可以被分解为多个子任务的任务。Fork-Join框架的核心思想是将一个大任务&#xff08;Task&#xff09;拆分成…