springboot定时服务

news2025/5/22 13:53:56

上一篇文章【修改定时时间,定时任务及时生效】  是定时任务与功能项目共用一个;

我目前所在公司的定时服务是专门有一个项目处理,然后定时查询库里面的定时信息配置。

话不多说,上程序

数据库设置

create table SCHEDULER_JOB
(
  id       VARCHAR2(32) not null,
  job_name VARCHAR2(200),
  cron     VARCHAR2(100),
  method_name varchar2(200),
  bean_name varchar2(200),
  remark varchar2(50),
  type varchar2(4) default '是否有参数 01否 02是'
)

实体类 SchedulerJob

package com.example.demo.entity;

public class SchedulerJob {

    private String id;
    //任务名称
    private String jobName;
    //表达式
    private String cron;
    //方法名称
    private String methodName;
    //bean名称
    private String beanName;
    //备注(方法的参数)
    private String remark;
    //类型 是否有参数 01否 02是
    private String type;

    //todo get/set方法
}

SchedulerJobMapper

import com.example.demo.entity.SchedulerJob;
import org.apache.ibatis.annotations.Mapper;

import java.util.List;

@Mapper
public interface SchedulerJobMapper {

    List<SchedulerJob> queryList();
}

SchedulerJobMapper.xml

<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.example.demo.mapper.SchedulerJobMapper">

    <resultMap type="com.example.demo.entity.SchedulerJob" id="resultMap">
        <result property="id" 			column="ID"/>
        <result property="jobName" 		column="JOB_NAME"/>
        <result property="cron"		column="CRON"/>
        <result property="methodName"		column="METHOD_NAME"/>
        <result property="beanName"		column="BEAN_NAME"/>
        <result property="remark"		column="REMARK"/>
        <result property="type"		column="TYPE"/>
    </resultMap>

    <select id="queryList" resultMap="resultMap">
        select ID,JOB_NAME,CRON,METHOD_NAME,BEAN_NAME,REMARK,TYPE from  scheduler_job
    </select>

</mapper>

JobRegisterService 用分布式锁定时查询定时任务

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.ValueOperations;
import org.springframework.integration.redis.util.RedisLockRegistry;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Lock;

@Service
public class JobRegisterService {

    private static final Logger logger = LoggerFactory.getLogger(JobRegisterService.class);

    @Autowired
    private RedisLockRegistry redisLockRegistry;

    @Autowired
    private RedisTemplate<String, Object> redisTemplate;

    @Autowired
    private JobService jobService;

    @Scheduled(cron = "0 0/2 * * * ?")
    public void startTaskJob() {
        Lock lock = redisLockRegistry.obtain("lock");
        try {
            boolean flag = lock.tryLock(10L, TimeUnit.SECONDS);
            ValueOperations<String, Object> map = redisTemplate.opsForValue();
            if (flag) {
                Object taskStatus = map.get("taskStatus");
                if (taskStatus != null && taskStatus.toString().equals("Y")) {
                    jobService.clearAllJob();
                    return;
                }
                map.set("taskStatus", "Y");
                redisTemplate.expire("taskStatus", 1L, TimeUnit.MINUTES);
                jobService.timeTask();
            } else {
                jobService.clearAllJob();
            }
        } catch (Exception e) {
            logger.error("获取锁异常:", e);
        } finally {
            lock.unlock();
        }
    }
}

JobService  查询数据库,并为每个job设置对应的表达式cron

import com.alibaba.fastjson.JSON;
import com.example.demo.entity.SchedulerJob;
import com.example.demo.mapper.SchedulerJobMapper;
import com.example.demo.util.DateUtils;
import org.quartz.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;

@Service
@Transactional
public class JobService {

    private static final Logger logger = LoggerFactory.getLogger(JobService.class);

    @Autowired
    private Scheduler scheduler;

    @Autowired
    private SchedulerJobMapper schedulerJobMapper;

    public void timeTask() {
        //查询数据库存在需要定时的任务
        logger.info("任务重置开始,查询数据...");
        List<SchedulerJob> schedulerJobList = schedulerJobMapper.queryList();
        if (schedulerJobList != null) {
            try {
                scheduler.clear();
                logger.info("任务重置开始,旧的任务清理");
                schedulerJobList.forEach(this::addJob);
            } catch (Exception e) {
                logger.error("调用错误:", e);
            }
        }
    }

    public void addJob(SchedulerJob schedulerJob) {
        try {
            //作业名称
            JobKey jobKey = JobKey.jobKey(schedulerJob.getJobName());
            //设置触发时间
            CronScheduleBuilder cronScheduleBuilder = CronScheduleBuilder.cronSchedule(schedulerJob.getCron());
            //触发建立
            Trigger trigger = TriggerBuilder.newTrigger().withIdentity(schedulerJob.getJobName()).withSchedule(cronScheduleBuilder).forJob(jobKey).build();
            if (trigger != null && trigger.getStartTime() != null) {
                logger.info("作业【{}】启动时间为{}", schedulerJob.getJobName(), DateUtils.formatDate(trigger.getStartTime(), DateUtils.DATETIME_FORMAT));
            } else {
                logger.info("作业【{}】启动时间为空", schedulerJob.getJobName());
            }
            //建立作业
            JobDetail jobDetail = JobBuilder.newJob(QuartzFactory.class).withIdentity(schedulerJob.getJobName()).build();
            jobDetail.getJobDataMap().put("schedulerJob", schedulerJob);
            //调度作业
            scheduler.scheduleJob(jobDetail, trigger);

            if (!scheduler.isShutdown()) {
                scheduler.start();
            }
        } catch (Exception e) {
            logger.error("添加作业失败[schedulerJob={}]", JSON.toJSONString(schedulerJob), e);
        }
    }

    /**
     * 清除任务
     */
    public void clearAllJob() throws SchedulerException {
        logger.info("清除任务...");
        scheduler.clear();
    }
}

QuartzFactory 定时任务工厂 根据method_name找到对应的映射信息,并执行该方法

import com.example.demo.constant.SchedulerJobTypeEnum;
import com.example.demo.entity.SchedulerJob;
import com.example.demo.util.SpringContextUtil;
import org.apache.commons.lang.StringUtils;
import org.quartz.Job;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;

import java.lang.reflect.Method;

@Component
public class QuartzFactory implements Job {

    private static final Logger logger = LoggerFactory.getLogger(QuartzFactory.class);

    @Override
    public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException {
        //获取调度数据
        SchedulerJob schedulerJob = (SchedulerJob) jobExecutionContext.getMergedJobDataMap().get("schedulerJob");
        //获取对应的bean
        Object obj = SpringContextUtil.getObj(schedulerJob.getBeanName());
        try {
            if (obj == null) {
                throw new Exception("找不到该类");
            }
            if (StringUtils.isEmpty(schedulerJob.getType()) || SchedulerJobTypeEnum.NO.getCode().equals(schedulerJob.getType())) {
                Method method = obj.getClass().getMethod(schedulerJob.getMethodName());
                method.invoke(obj);
            } else {
                Method method = obj.getClass().getMethod(schedulerJob.getMethodName(), String.class);
                method.invoke(obj, schedulerJob.getRemark());
            }
        } catch (Exception e) {
            logger.error("定时任务获取映射异常:", e);
        }
    }
}

SpringContextUtil 上下文工具

import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Component;

@Component
public class SpringContextUtil implements ApplicationContextAware {

    //spring 上下文实例对象
    private static ApplicationContext context;

    // 根据class获取对象实例
    public static <T> T getObj(Class<T> tClass) {
        return context.getBean(tClass);
    }

    // 根据配置的 bean name 获取对象实例
    public static Object getObj(String beanName) {
        return context.getBean(beanName);
    }

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        context = applicationContext;
    }
}

RedisLockConfig Redis分布式锁配置bean

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.integration.redis.util.RedisLockRegistry;

@Configuration
public class RedisLockConfig {

    @Bean
    public RedisLockRegistry redisLockRegistry(RedisConnectionFactory redisConnectionFactory) {
        //第一个参数redisConnectionFactory
        //第二个参数registryKey,分布式锁前缀,设置为项目名称会好些
        //该构造方法对应的分布式锁,默认有效期是60秒.可以自定义
        return new RedisLockRegistry(redisConnectionFactory, "demo");
    }
}

SchedulerConfig 定时任务配置bean

import org.quartz.Scheduler;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.quartz.SchedulerFactoryBean;

import java.io.IOException;

@Configuration
public class SchedulerConfig {

    @Bean
    public Scheduler scheduler() throws Exception {
        Scheduler scheduler = schedulerFactoryBean().getScheduler();
        return scheduler;
    }

    @Bean
    public SchedulerFactoryBean schedulerFactoryBean() throws IOException {
        SchedulerFactoryBean factory = new SchedulerFactoryBean();
        factory.setSchedulerName("Test_Scheduler");
        //覆盖已存在的任务
        factory.setOverwriteExistingJobs(true);
        // 延迟10s执行 防止发生系统未启动完成 定时任务却已经开始的情况
        factory.setStartupDelay(10);
        return factory;
    }
}

SchedulerJobTypeEnum 定时任务类型枚举

public enum SchedulerJobTypeEnum {

    NO("01", "否"),
    YES("02", "是");

    private String code;
    private String value;

    SchedulerJobTypeEnum(String code, String value) {
        this.code = code;
        this.value = value;
    }

    public String getCode() {
        return code;
    }

    public void setCode(String code) {
        this.code = code;
    }

    public String getValue() {
        return value;
    }

    public void setValue(String value) {
        this.value = value;
    }
}

DateUtils 时间处理工具类

import org.apache.commons.lang.time.DateFormatUtils;

import java.util.Date;

public class DateUtils {

    public static final String DATE_FORMAT = "yyyy-MM-dd";

    public static final String DATETIME_FORMAT = "yyyy-MM-dd HH:mm:ss";

    public static final String TIME_FORMAT = "HH:mm:ss";

    /**
     * 常用的时间格式.
     */
    private static String[] parsePatterns = {"yyyy-MM-dd",
            "yyyy-MM-dd HH:mm:ss",
            "yyyy-MM-dd HH:mm",
            "HH:mm:ss"};

    /**
     * 得到当前日期字符串.
     */
    public static String getDate() {
        return getDate(DateUtils.DATE_FORMAT);
    }

    public static String getDate(String pattern) {
        return DateFormatUtils.format(new Date(), pattern);
    }

    /**
     * 得到当前时间字符串.
     */
    public static String getTime() {
        return formatDate(new Date(), DateUtils.TIME_FORMAT);
    }

    /**
     * 得到当前日期和时间字符串.
     */
    public static String getDateTime() {
        return formatDate(new Date(), DateUtils.DATETIME_FORMAT);
    }

    /**
     * 获取日期时间字符串,默认格式为(yyyy-MM-dd).
     */
    public static String formatDate(Date date, Object... pattern) {
        String formatDate = null;
        if (pattern != null && pattern.length > 0) {
            formatDate = DateFormatUtils.format(date, pattern[0].toString());
        } else {
            formatDate = DateFormatUtils.format(date, DateUtils.DATE_FORMAT);
        }
        return formatDate;
    }
}

TestSchedulerJobService 定义的定时任务方法

import com.example.demo.util.DateUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;

@Service
public class TestSchedulerJobService {

    private static final Logger logger = LoggerFactory.getLogger(TestSchedulerJobService.class);

    public void test() {
        String dateTime = DateUtils.getDateTime();
        logger.info("当前时间={}", dateTime);
    }

    public void test1(String param) {
        String dateTime = DateUtils.getDateTime();
        logger.info("当前时间1={},参数={}", dateTime, param);
    }
}

数据库补充数据

【注意:】数据库中bean_Name存储的是bean名称(默认类名首字母小写)

job_name和method_name数据值一样即可

 测试结果

 由此可看出,两个定时任务是按照数据库中配置的定时时间跑的。

具体定时任务时间等信息视情况而定!

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

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

相关文章

mac-Yarn安装成功但提示 command not found 解决方案

文章目录 查看yarn配置卸载yarn删除注册表清除yarn缓存npm安装yarn安装完成后yarn -v提示command not found&#xff0c;故选择使用命令重新安装命令安装yarn然后打开.bash_profile文件&#xff1a;参考&#xff1a;https://www.python100.com/html/119013.html 最近遇到项目使…

软件测试下的AI之路(3)

&#x1f60f;作者简介&#xff1a;博主是一位测试管理者&#xff0c;同时也是一名对外企业兼职讲师。 &#x1f4e1;主页地址&#xff1a;【Austin_zhai】 &#x1f646;目的与景愿&#xff1a;旨在于能帮助更多的测试行业人员提升软硬技能&#xff0c;分享行业相关最新信息。…

cmd打开idea

当我们用idea打开一个项目的时候&#xff0c;有时候这个项目目录是有的&#xff0c;但是用idea的open却找不到&#xff0c;有时候我要重新关闭窗口&#xff0c;再open好多次才有 于是我现在使用命令打开&#xff0c;先把idea安装路径的bin目录放在path里面 然后cd到项目路径&…

【ubuntu 快速熟悉】

ubuntu 快速熟悉 2.ubuntu桌面管理器3.ubuntu常见文件夹说明4.ubuntu任务管理器4.1 gnome桌面的任务管理器4.2 实时监控GPU4.3 top 命令 5.ubuntu必备命令5.1 .deb文件5.2 查找命令5.2.1 find文件搜索5.2.2 which查找可执行文件的路径5.2.3 which的进阶&#xff0c;whereis5.2.…

linux:使用nc(netcat)命令进行端口检测,并使用Docker管理容器

需求&#xff1a; 循环检测IP:端口是否能正常连接&#xff0c;能连接则关闭docker服务&#xff0c;不能连接则开启docker服务实现&#xff1a;  &esmp;通过创建linux可执行shell脚本文件&#xff0c;再设置crontab调度执行实现上述需求。详细步骤如下&#xff1a; 创建sh…

ChatGPT Plus的Vision升级是一个改变游戏规则的创举

内容来源&#xff1a;0xluffy_eth ChatGPT Plus的Vision升级是一个改变游戏规则的创举&#xff01; 现在每个用户都可以以每月20美元的价格雇用自己的个人数字助理实习生&#xff0c;具备VISION&#xff01; 以下是10个惊人的例子&#xff08;&#xff09; 1&#xff0c; 我…

Java时间工具类:ZTDateTimeUtil

目录 1.返回指定格式的当前时间,Date-->FormatString,Date类型转Strig 2.返回固定格式的Date类型时间Date---》ToString---》ToDate,Date类型格式化成Date 3.字符串转日期 String格式化成String 4.两时间关系判断构件 5.Date转换为字符串:Date格式化成String 6.String类…

创建第一个Go的程序Hello Kitty

上一篇&#xff0c;我们已经搭建好了开发要用的基础环境:Go开发基础环境搭建, 今天我们要开始用GoLand实操关于Go的代码开发。 创建工程 File > New > Project 其中 game为项目名称 在项目目录下会自动生成一个文件:go.mod ,模块是相关Go包的集合。modules是源代码交换…

Exploration by random network distillation论文笔记

Exploration by Random Network Distillation (2018) 随机网络蒸馏探索 0、问题 这篇文章提出的随机网络蒸馏方法与Curiosity-driven Exploration by Self-supervised Prediction中提出的好奇心机制的区别&#xff1f; 猜想&#xff1a;本文是基于随机网络蒸馏提出的intrin…

在GORM中使用并发

一个全面的指南&#xff0c;如何安全地使用GORM和Goroutines进行并发数据处理 效率是现代应用程序开发的基石&#xff0c;而并发在实现效率方面发挥着重要作用。GORM&#xff0c;这个强大的Go对象关系映射库&#xff0c;使开发人员能够通过Goroutines embrace并行性。在本指南…

Docker进阶——再次认识docker的概念 Docker的结构 Docker镜像结构 镜像的构建方式

前言 在微服务大量应用的互联网时代&#xff0c;经常能看到docker的身影。作为docker的爱好者&#xff08;在服务器安装MySQL&#xff0c;Redis。。。我用的都是docker&#xff09;&#xff0c;我也会持续深入学习和认识docker。 本篇博客再次介绍docker的基本概念&#xff0…

在ubuntu sudo apt-get update 更新报错

sudo apt-get update 更新报错 解决办法&#xff1a; 用你自己的key 根据上图自己找 sudo gpg --keyserver keyserver.ubuntu.com --recv-keys **********运行完成有一个ok 见下图 运行命令&#xff0c;中间的还是上面的key复制下来即可 sudo gpg --export --armor **********…

DAY50 309.最佳买卖股票时机含冷冻期 + 714.买卖股票的最佳时机含手续费

309.最佳买卖股票时机含冷冻期 题目要求&#xff1a;给定一个整数数组&#xff0c;其中第 i 个元素代表了第 i 天的股票价格 。 设计一个算法计算出最大利润。在满足以下约束条件下&#xff0c;你可以尽可能地完成更多的交易&#xff08;多次买卖一支股票&#xff09;: 你不…

补偿 FIR 滤波器引入的延迟

补偿 FIR 滤波器引入的延迟 对信号进行滤波会引入延迟。这意味着相对于输入&#xff0c;输出信号在时间上有所偏移。此示例向您说明如何抵消这种影响。 有限冲激响应滤波器经常将所有频率分量延迟相同的时间量。这样&#xff0c;我们就很容易通过对信号进行时移处理来针对延迟…

动态规划学习——多状态dp(打家劫舍问题)

一&#xff0c;打家劫舍I 题目&#xff1a; 一个专业的小偷&#xff0c;计划偷窃沿街的房屋。每间房内都藏有一定的现金&#xff0c;影响小偷偷窃的唯一制约因素就是相邻的房屋装有相互连通的防盗系统&#xff0c;如果两间相邻的房屋在同一晚上被小偷闯入&#xff0c;系统会自…

【科研绘图】MacOS上的LaTeX公式插入工具——LaTeXiT

在Mac上经常用OmniGraffle绘图&#xff0c;但是有个致命缺点是没办法插入LaTeX公式&#xff0c;很头疼。之前有尝试用Pages文稿插入公式&#xff0c;但是调字体和颜色很麻烦。并且&#xff0c;PPT中的公式插入感觉也不太好看。 偶然机会了解到了LaTeXiT这个工具&#xff0c;可…

11月份 四川汽车托运报价已经上线

中国人不骗中国人!! 国庆小长假的高峰期过后 放假综合症的你还没痊愈吧 今天给大家整理了9条最新线路 广州到四川的托运单价便宜到&#x1f4a5; 核算下来不过几毛钱&#x1f4b0; 相比起自驾的漫长和疲惫&#x1f697; 托运不得不说真的很省事 - 赠送保险 很多客户第一次运车 …

上海亚商投顾:沪指缩量震荡 龙字辈个股掀跌停潮

上海亚商投顾前言&#xff1a;无惧大盘涨跌&#xff0c;解密龙虎榜资金&#xff0c;跟踪一线游资和机构资金动向&#xff0c;识别短期热点和强势个股。 一.市场情绪 三大指数全天窄幅震荡&#xff0c;沪指最终微幅收红&#xff0c;深成指、创业板指小幅下跌。煤炭板块集体大涨…

pip无法下载moviepy -无法联网

猜测是无法联网 尝试更新匹配 ——失败 尝试1&#xff1a;从网络下载whl文件——还需要下载相关依赖&#xff0c;过于麻烦 但应该可行 下载地址 https://pypi.tuna.tsinghua.edu.cn/simple/对应的包名/ 可能会出现如下&#xff0c;然后继续挨个找 尝试2&#xff1a;使pip联网…

基于若依的ruoyi-nbcio流程管理系统仿钉钉流程json转bpmn的flowable的xml格式(支持并行网关)

更多ruoyi-nbcio功能请看演示系统 gitee源代码地址 前后端代码&#xff1a; https://gitee.com/nbacheng/ruoyi-nbcio 演示地址&#xff1a;RuoYi-Nbcio后台管理系统 这个章节来完成并行网关&#xff0c;前端无需修改&#xff0c;直接后端修改就可以了。 1、并行网关后端修…