springboot定时服务

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

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

话不多说,上程序

数据库设置

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数据值一样即可

 测试结果

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

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

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

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

相关文章

基于springboot 手工艺品在线展示系统-计算机毕设 附源码 42553

springboot 手工艺品在线展示系统 目 录 摘要 1 绪论 1.1本课题研究意义 1.2系统开发目的 2 1.3系统开发技术的特色 3 1.4 springboot框架介绍 3 1.5论文结构与章节安排 4 2 手工艺品在线展示系统系统分析 5 2.1 可行性分析 5 2.2 系统流程分析 5 2.2.1数据增加流程 5 2.2.…

Swift 抛砖引玉:从数组访问越界想到的“可抛出错误”属性

0. 概览 了解 Swift 语言的小伙伴们都知道&#xff0c;我们可以很方便的写一个可能抛出错误的方法。不过大家可能不知道的是在 Swift 中对于结构或类的实例属性我们也可以让它抛出错误。 这称之为实效只读属性&#xff08;Effectful Read-only Properties&#xff09;。 那么…

速锐得柴油发动机车辆数据的实时获取定位和运行状态监测设计思路

随着港口、油田、车队运输、物流及冷链等多种交通运输领域的兴起&#xff0c;保障性集团运输业务在这些领域凸显出重要的作用&#xff0c;数字化转型及平台系统性管理要求越来越高&#xff0c;针对柴油发动机车辆数据的实时获取定位和运行状态的检测方案配套平台系统&#xff0…

DSP开发例程(4): logbuf_print_to_uart

目录 DSP开发例程: logbuf_print_to_uart新建工程源码编辑app.cfgos.cmain.c 调试说明 DSP开发例程: logbuf_print_to_uart SYS/BIOS 提供了 xdc.runtime.Log, xdc.runtime.LoggerBuf 和 xdc.runtime.LoggerSys 这几个模块用于日志记录. 日志信息在 应用程序调试和状态监控中非…

用友NC Cloud accept.jsp接口任意文件上传漏洞复现 [附POC]

文章目录 用友NC Cloud accept.jsp接口任意文件上传漏洞复现 [附POC]0x01 前言0x02 漏洞描述0x03 影响版本0x04 漏洞环境0x05 漏洞复现1.访问漏洞环境2.构造POC3.复现 0x06 修复建议 用友NC Cloud accept.jsp接口任意文件上传漏洞复现 [附POC] 0x01 前言 免责声明&#xff1a…

万宾科技内涝积水监测仪使用效果一览

当一个城市突降暴雨&#xff0c;对城市管理部门来讲首当其中的是防止积水成患。随着城市人口快速增长&#xff0c;基础设施建设也日益受到更多的关注&#xff0c;城市内涝问题频繁增加&#xff0c;会给城市带来严重的经济损失和人员的安全问题。城市生命线工程建设过程中&#…

【EI会议征稿】第八届先进能源科学与自动化国际研讨会(AESA 2024)

第八届先进能源科学与自动化国际研讨会&#xff08;AESA 2024) 2024 8th International Workshop on Advances in Energy Science and Automation 继AESA 2017-2023相继成功举办之后&#xff0c;来自国内外多所高校、科研院所及企业代表在先进能源科学与自动化的科研合作和交流…

(附源码)基于spring boot 房屋租赁系统小程序-计算机毕设 88306

spring boot 房屋租赁系统小程序 目 录 摘要 1 绪论 1.1选题意义 1.2开发现状 1.3springboot框架介绍 1.4论文结构与章节安排 2 房屋租赁系统小程序系统分析 2.1 可行性分析 2.1.1 技术可行性分析 2.1.2 经济可行性分析 2.1.3 法律可行性分析 2.2 系统功能分析 2.…

VINS-Mono-后端优化 (三:视觉雅可比推导)

用逆深度是因为这样可以在优化中从优化3个变量降低到1个&#xff0c;降低优化的维度加快求解速度 用逆深度是因为当距离很远的时候&#xff0c; 1 x \frac{1}{x} x1​ x x x 就会无穷大&#xff0c;而3D点很近的情况也一般不会有&#xff0c;这也是为了数值稳定性 用逆深度的…

SAP 20策略测试简介

20策略相信也有很多小伙伴使用过,与50最大的不同之处就在于20策略是不能做计划独立需求的。 我看一下系统中20 策略的配置图,可以看到独立需求这里的配置都是空的。 1、我们开始测试准备物料 成品物料AB4 原材料:100197 2、创建BOM—CS01 3、创建主配方—c201 ,离散制造…

创建第一个Go的程序Hello Kitty

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

R | R包安装报错-github连接速度慢或无法访问 | metaboanalystR | Retip | rJava安装

R | R包安装报错-github连接速度慢或无法访问 | metaboanalystR | Retip | rJava安装 一、metaboanalystR 安装1.1 Bioconductor报错&#xff0c;无网络连接1.2 github520-修改hosts文件 二、retip安装2.1 rJava包加载报错及安装2.2 安装Retip包 三、从Bioconductor安装Rdisop报…

web3 前端dapp从redux过滤出 (我创建与别人创建)正在执行的订单 并展示在Table上

上文 web3 从redux中拿出所有已完成订单 并渲染到对应的Table列表中 我们从redux中 取出并渲染了 已完成的订单 那么 我们继续 万里长征 就快看到尽头了呀 我们先起一下环境 ganache 终端输入 ganache -d然后 登一下 MetaMask 然后 打开我们的项目 发布一下合约 truffle mig…

GZ038 物联网应用开发赛题第4套

2023年全国职业院校技能大赛 高职组 物联网应用开发 任 务 书 &#xff08;第4套卷&#xff09; 工位号&#xff1a;______________ 第一部分 竞赛须知 一、竞赛要求 1、正确使用工具&#xff0c;操作安全规范&#xff1b; 2、竞赛过程中如有异议&#xff0c;可向现场考评…

SAP 50策略测试简介

上篇博文写了40策略的测试,40策略就是典型的按库存生产,考虑库存,考虑销售订单。 本文将测试50策略,按单生产用的最多的策略。相信很多公司按单生产应该都会用到50的策略 1、首先还是先创建物料AB3 同时将BOM中的原材料的独立集中的字段设置为1 2、创建BOM—CS01 3、同杨…

动态通讯录及程序保存在文件中

目录 一、结构体改造及增容函数 1.结构体部分 2.初始化函数及增容函数 二、信息添加及销毁和排序 1.信息添加函数&#xff08;Add&#xff09; 2.销毁函数&#xff08;Destroy&#xff09; 3.排序部分&#xff08;qsort&#xff09; 三、通讯录信息保存 1.保存在文件中…

【华为数通HCIP | 网络工程师】821-BGP 组播高频题与解析(1)

个人名片&#xff1a; &#x1f43c;作者简介&#xff1a;一名大三在校生&#xff0c;喜欢AI编程&#x1f38b; &#x1f43b;‍❄️个人主页&#x1f947;&#xff1a;落798. &#x1f43c;个人WeChat&#xff1a;hmmwx53 &#x1f54a;️系列专栏&#xff1a;&#x1f5bc;️…

在线直线度测量仪为什么在轧钢行业越来越受欢迎!

在线直线度测量仪是利用光电检测原理及直线法进行直线度尺寸精密检测的。其测量方法是前后两台测量仪测量的数据拟合一条直线&#xff0c;中间的测量仪所测数值与直径做对比&#xff0c;即可得到被测物的直线度尺寸。 在线直线度测量仪的优点 在线直线度测量仪是一种三台小测…

Vue生命周期全解析:从工厂岗位到任务执行,一览无遗!

&#x1f3ac; 江城开朗的豌豆&#xff1a;个人主页 &#x1f525; 个人专栏 :《 VUE 》 《 javaScript 》 &#x1f4dd; 个人网站 :《 江城开朗的豌豆&#x1fadb; 》 ⛺️ 生活的理想&#xff0c;就是为了理想的生活 ! 目录 ⭐ 专栏简介 &#x1f4d8; 文章引言 一、生…

Bean的循环依赖问题

2023.11.10 通俗来讲&#xff0c;循环依赖指的是一个实例或多个实例存在相互依赖的关系&#xff08;类之间循环嵌套引用&#xff09;。比如&#xff1a;丈夫类Husband&#xff0c;妻子类Wife。Husband中有Wife的引用。Wife中有Husband的引用。 正常调用这两对象不会出现问题&am…