定时任务配置技巧:将表达式配置在业务员代码之外的方法

本文涉及的产品
云数据库 RDS MySQL,集群系列 2核4GB
推荐场景:
搭建个人博客
RDS MySQL Serverless 基础系列,0.5-2RCU 50GB
云数据库 RDS PostgreSQL,集群系列 2核4GB
简介: 该文档介绍了三种不同的方法来定义和管理Java中的定时任务。首先,通过在数据库中创建一个表来存储定时任务的执行周期,并在Spring Boot应用中使用`@Scheduled`注解配合数据库查询来动态执行定时任务。其次,将定时任务的配置移动到Apollo配置中心,利用Apollo的配置能力来控制定时任务的执行。最后,使用Quartz框架并结合Apollo配置文件,动态地管理定时任务的触发间隔和执行时间。此外,还提到了在多机器环境中,可以使用分布式锁来避免任务重复,并推荐了xxl-JOB和elastic-job作为更专业的定时任务解决方案。

 1、 定义在数据库中

1、导入依赖包:

<parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter</artifactId>
        <version>2.0.4.RELEASE</version>
    </parent>
    <dependencies>
        <dependency><!--添加Web依赖 -->
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency><!--添加MySql依赖 -->
             <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
        </dependency>
        <dependency><!--添加Mybatis依赖 配置mybatis的一些初始化的东西-->
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter</artifactId>
            <version>1.3.1</version>
        </dependency>
        <dependency><!-- 添加mybatis依赖 -->
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis</artifactId>
            <version>3.4.5</version>
            <scope>compile</scope>
        </dependency>
    </dependencies>

image.gif

2、添加数据库记录:

开启本地数据库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 * * * * ?');

image.gif

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

image.gif

3、创建定时器

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

具体代码如下:

@Configuration      //1.主要用于标记配置类,兼备Component的效果。
@EnableScheduling   // 2.开启定时任务
public class DynamicScheduleTask implements SchedulingConfigurer {
    @Mapper
    public interface CronMapper {
        @Select("select cron from cron limit 1")
        public String getCron();
    }
    @Autowired      //注入mapper
    @SuppressWarnings("all")
    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);
                }
        );
    }
}

image.gif

2、定义在Apollo中:

package com.Schedule;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import javax.annotation.PostConstruct;
import java.time.LocalDateTime;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
/**
 * @Description :定时任务配置在Apollo
 * @Author lishuangqiang
 * @Date 2021/1/26
 **/
@Slf4j
@Component
public class DynamicScheduleTaskInApollo {
    /**
     * 其中corntest为配置在Apollo上的corn表达式
     */
    @Scheduled(cron = "${corntest}")
    public void test1() {
        log.info("定时任务开始 :{} ,线程 : {}", LocalDateTime.now().toLocalTime());
    }
    @Value("${timeApollo}")
    private Long timeApollo;
    @PostConstruct
    public void test2() {
        ScheduledExecutorService scheduledThreadPool = Executors.newScheduledThreadPool(2);
        scheduledThreadPool.scheduleAtFixedRate(new Runnable() {
            @Override
            public void run() {
                log.info("handleRemindWay2定时任务开始 :{} ,线程 : {}", LocalDateTime.now().toLocalTime(), Thread.currentThread().getName());
                log.info("=========================");
            }
        }, timeApollo, timeApollo, TimeUnit.MILLISECONDS);
    }
}

image.gif

3、用quartz方式 其中定时任务的表达式也可以配置在Apollo

@Configuration
public class QuartzConfig {
 
 
    @Resource
    private ScheduleTask scheduleTask;
 
    /**
     * 配置定时任务1
     * @return
     */
    @Bean(name="firstJobDetail")
    public MethodInvokingJobDetailFactoryBean firstJobDetail(){
        MethodInvokingJobDetailFactoryBean method = new MethodInvokingJobDetailFactoryBean();
        // 为需要执行的实体类对应的对象
        method.setTargetObject(scheduleTask);
        // 需要执行的方法
        method.setTargetMethod("test");
        // 是否并发执行
        method.setConcurrent(false);
        return method;
    }
 
 
    /**
     *   配置触发器1
     *   @param firstJobDetail
     *   @return
     */
    @Bean(name="firstTrigger")
    public SimpleTriggerFactoryBean firstTrigger(JobDetail firstJobDetail){
        SimpleTriggerFactoryBean simpleBean = new SimpleTriggerFactoryBean();
        simpleBean.setJobDetail(firstJobDetail);
        // 设置任务启动延迟
        simpleBean.setStartDelay(1000);
        // 每1秒执行一次
        simpleBean.setRepeatInterval(1000);
        //设置重复计数
        //simpleBean.setRepeatCount(0);
        return simpleBean;
    }
 
    /**
     *  配置Scheduler
     */
    @Bean(name = "scheduler")
    public SchedulerFactoryBean schedulerFactoryBean(Trigger firstTrigger){
        SchedulerFactoryBean factoryBean = new SchedulerFactoryBean();
        factoryBean.setTriggers(firstTrigger);
        return factoryBean;
    }
 
 
 
}

image.gif

@Component
public class ScheduleTask {
 
   public void test() {
       System.out.println("====================================");
   }
 
}

image.gif

4、把参数配置到.properties文件中

package com.accord.task;
 
import java.text.SimpleDateFormat;
import java.util.Date;
 
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
 
@Component
public class ScheduledTask {
 
  private static final SimpleDateFormat dateFormat = new SimpleDateFormat("HH:mm:ss");
 
  //@Scheduled(fixedDelayString = "${jobs.fixedDelay}")
  @Scheduled(fixedDelayString = "2000")
  public void getTask1() {
    System.out.println("任务1,从配置文件加载任务信息,当前时间:" + dateFormat.format(new Date()));
  }
 
  @Scheduled(cron = "${jobs.cron}")
  public void getTask2() {
    System.out.println("任务2,从配置文件加载任务信息,当前时间:" + dateFormat.format(new Date()));
  }
}

image.gif

application.properties文件:

jobs.fixedDelay=5000
jobs.cron=0/5 * *  * * ?

image.gif

上面的方式在做定时任务 时有多个机器最好用redission做分布式锁方式防止重复调用,当然这样的情况最好用业界的xxl-JOB或者elastic-job,最好,支持分片配置

借鉴:https://www.cnblogs.com/mmzs/p/10161936.html

java定时任务实现的4种方式_scheduledthreadpool.scheduleatfixedrate(timertask,-CSDN博客,还要自己的之前的东西

相关实践学习
如何在云端创建MySQL数据库
开始实验后,系统会自动创建一台自建MySQL的 源数据库 ECS 实例和一台 目标数据库 RDS。
全面了解阿里云能为你做什么
阿里云在全球各地部署高效节能的绿色数据中心,利用清洁计算为万物互联的新世界提供源源不断的能源动力,目前开服的区域包括中国(华北、华东、华南、香港)、新加坡、美国(美东、美西)、欧洲、中东、澳大利亚、日本。目前阿里云的产品涵盖弹性计算、数据库、存储与CDN、分析与搜索、云通信、网络、管理与监控、应用服务、互联网中间件、移动服务、视频服务等。通过本课程,来了解阿里云能够为你的业务带来哪些帮助 &nbsp; &nbsp; 相关的阿里云产品:云服务器ECS 云服务器 ECS(Elastic Compute Service)是一种弹性可伸缩的计算服务,助您降低 IT 成本,提升运维效率,使您更专注于核心业务创新。产品详情: https://www.aliyun.com/product/ecs
目录
相关文章
|
3月前
|
C#
C# 跳过值班时间代码逻辑
C# 跳过值班时间代码逻辑
31 0
|
5月前
|
弹性计算 运维 Serverless
函数计算产品使用问题之如何自己设置定时任务
函数计算产品作为一种事件驱动的全托管计算服务,让用户能够专注于业务逻辑的编写,而无需关心底层服务器的管理与运维。你可以有效地利用函数计算产品来支撑各类应用场景,从简单的数据处理到复杂的业务逻辑,实现快速、高效、低成本的云上部署与运维。以下是一些关于使用函数计算产品的合集和要点,帮助你更好地理解和应用这一服务。
|
6月前
|
弹性计算 运维 监控
|
6月前
修正flowable流程支持节点表单字段条件判断
修正flowable流程支持节点表单字段条件判断
91 0
|
6月前
|
SQL 监控 测试技术
Lim测试平台变量使用规则介绍
Lim测试平台变量使用规则介绍
62 0
27activiti - 流程变量(查询历史的流程变量)
27activiti - 流程变量(查询历史的流程变量)
57 0
|
SQL 安全 前端开发
案例07-在线人员列表逻辑混乱-ThreadLocal、继承、索引失效
案例07-在线人员列表逻辑混乱-ThreadLocal、继承、索引失效
|
消息中间件 JavaScript 小程序
接了个变态需求:给定一个接口,要用户自定义动态实现并上传热部署,怎么搞?
接了个变态需求:给定一个接口,要用户自定义动态实现并上传热部署,怎么搞?
|
调度
错误:“产品订单的调度参数没有被定义”
信息错误信息:产品订单的调度参数没有被定义消息号 CT604诊断在定制工厂1000,订单类型ZP91和生产调度员*的过程中,没有为生产订单定义计划级别。只有输入了详细计划、粗略计划或生产率计划的选择标识,才能实施计划。
1506 0
|
前端开发
前端工作总结263-判断绑定逻辑
前端工作总结263-判断绑定逻辑
53 0