SpringBoot整合定时器:定时任务不再硬编码,动态定时刷起来

本文涉及的产品
服务治理 MSE Sentinel/OpenSergo,Agent数量 不受限
可观测可视化 Grafana 版,10个用户账号 1个月
简介: 前言传统定时器是硬编码。但是有的时候业务上需要不断地调整问题描述我们开发了一个定闹钟的功能。这个功能肯定是定时器开发。但是这就存在一个问题这个定时是动态的。那么我们如何实现呢?请接着看

前言

  • 传统定时器是硬编码。但是有的时候业务上需要不断地调整

问题描述

  • 我们开发了一个定闹钟的功能。这个功能肯定是定时器开发。但是这就存在一个问题这个定时是动态的。那么我们如何实现呢?请接着看

简介

  • 定时器在开发中真的算是一种福利了。通过定时器我们省去了很多人力。我们通过定时器将一些繁琐定期的事情通过代码去完成。在Java开发中我们通过Timer类可以简单实现定时器功能。既然是springboot课程今天我们就来看看srpingboot整合定时器的事情

传统定时器

  • 这里使用的是之前课程一的配置。springboot打算是系列讲解。所以配置都是承前启后的。建议大家按顺序观看。
@Component
public class SimpleSchedule {
    @Autowired
    TestMapper testMapper;
    @Scheduled(cron = "*/6 * * * * ?")
    private void process() {
        List<test> tests = testMapper.getTests();
        System.out.println(tests);
    }
}
  • 定时器的编写也很简单,只需要在类或者方法上加上@Scheduled注解。然后配置cron表达式就可以了。这里得注意一下需要在spirngboot启动类上加上开发定时器的注解。
@SpringBootApplication
public class CrontabApplication {
    public static void main(String[] args) {
        SpringApplication.run(CrontabApplication.class, args);
    }
}

  • 代码中我们使用的是最简单的一种方式。
  • cron表达式:指定任务在特定时间执行
  • fixedDelay:表示上一次任务执行完成后多久再执行,参数类型long,单位:ms
  • fixedDelayString:与fixedDelay一样,只是参数类型是String
  • fixedRate:表示按一定的频率执行任务,参数类型long,单位:ms 如: fixedRate(5000),表示这个定时器任务每5秒执行一次
  • fixedRateString:与fixedRate一样,只是参数类型变为String
  • initialDelay:表示延迟多久再第一次执行任务,参数类型为long ,单位:ms
  • initialDelayString:与initialDelay一样,只是参数类型String

动态定时器

  • 上面的定时器已经成功的配置了。但是现在有一个需求客户想通过页面定制配置定时器执行的频率。上面代码我们是写死6S执行一次。如果客户想通过可视化配置。配置完成之后我总不能再手动改写代码吧。那么动态定时器就产生了。

V1.0

  • 既然动态我们就得将客户配置的数据进行本地化。当然是存储在数据库中。

  • 对应的我们新建Mapper查询定时任务信息。因为这里只配置了表达式。没有配置表达式对应的定时器。也是为了测试。这里默认表达式就是一个。
@Configuration
public class ScheduleConfigV1 implements SchedulingConfigurer {
    @Autowired
    CronMapper cronMapper;
    @Autowired
    TestMapper testMapper;
    @Override
    public void configureTasks(ScheduledTaskRegistrar scheduledTaskRegistrar) {
        scheduledTaskRegistrar.addTriggerTask(()-> {
                    System.out.println("执行定时器任务:" + LocalDateTime.now().toLocalTime());
                    List<test> tests = testMapper.getTests();
                    System.out.println(tests);
                },
                triggerContext -> {
                    List<cron> crons = cronMapper.getCron();
                    Cron cron = crons.get(0);
                    return new CronTrigger(cron.getCron()).nextExecutionTime(triggerContext);
                });
    }
}
  • 执行这个代码我们最好先关掉前面那个静态的定时器。这样看的效果明显点。首先数据库配置的是6秒执行一次。然后把数据改成2秒执行一次。看看效果。

  • 我们发现只要数据库信息修改了。定时任务会自动修改频率的。最重要的是不需要重启我们的代码。
  • 上面虽然是动态配置了。但是有一个缺点。就是修改之后生效是在下一次触发定时器执行后有效。说白了就是一开始一小时执行一次,在这期间修改了不能立马生效必须得到下一次一小时才会去刷新配置。这里的动态可以理解成懒动态。

V2.0

  • 上面的功能虽然是动态的。但是对于量产的话肯定是不科学的。首先数据库不可能只存一条数据的。
  • 如果存多条数据那么多条定时规则与具体的定时器怎么进行匹配呢?
  • 既然是动态的那么如何通过数据库控制定时器的开关呢?
  • 定时任务的通过代码启动实际是scheduler.schedule(task, new CronTrigger("*/2 * * * * ?"));实现的。这个方法返回的对象是ScheduledFuture。通过canel方法取消定时任务。基于这两个方法我们来改进下我们之前的定时任务。

Registar

  • 首先我们提供一个注册器,注册器的功能就是管理定时任务。提供增加删除功能。在增加定时器的节点上我们调用scheduler.schedule(task, new CronTrigger("*/2 * * * * ?"));来启动定时任务。在删除节点上调用之前获取的ScheduledFuture来canel这个定时任务。这样做的好处我们可以随时控制定时任务的开关
public void addCronTask(Runnable task, String cron) {
    addCronTask(new CronTask(task,cron));
}
  • 上面添加需要有一个runnable和cron表达式。用一个ConcurrentHashMap来管理添加进来的runnable。runnable为key,ScheduledTask为值。
public ScheduledTask scheduleCronTask(CronTask cronTask) {
    ScheduledTask scheduledTask;
    scheduledTask = new ScheduledTask();
    scheduledTask.future = this.taskScheduler.schedule(cronTask.getRunnable(), cronTask.getTrigger());
    return scheduledTask;
  }
  • 这样构建一个ScheduledTask对象。
public final class ScheduledTask {
    public volatile ScheduledFuture<!--?--> future;
    /**
     * 取消定时任务
     */
    public void cancel() {
        ScheduledFuture<!--?--> future = this.future;
        if (future != null) {
            future.cancel(true);
        }
    }
}
  • 这样我们就可以通过构建一个runnable线程,结合表达式通过注册器注册就可以开启这个线程已固定频率执行。通过remove关闭线程。
SchedulingRunnable task = new SchedulingRunnable(TestMapper.class, "getTests", null);
cronTaskRegistrar.addCronTask(task, "0/10 * * * * ?");
  • 这样做的好处是我们可以在表数据修改的情况下立马更新定时任务规则。

总结

-上面的代码已经上传至gitee
点我传送
https://gitee.com/zxhTom/crontab.git

  • 下面Java类是我们这次使用用到的类。
  • SchedulingConfigurer
  • DisposableBean
  • ConcurrentHashMap

本文就是愿天堂没有BUG给大家分享的内容,大家有收获的话可以分享下,想学习更多的话可以到微信公众号里找我,我等你哦。

相关文章
|
1月前
|
Java 调度 Spring
SpringBoot实现多线程定时任务动态定时任务配置文件配置定时任务
SpringBoot实现多线程定时任务动态定时任务配置文件配置定时任务
274 0
|
5月前
|
Java 开发工具 git
spring boot 集成 ctrip apollo 实现动态配置更新
spring boot 集成 ctrip apollo 实现动态配置更新
50 1
|
24天前
|
安全 数据安全/隐私保护
Springboot+Spring security +jwt认证+动态授权
Springboot+Spring security +jwt认证+动态授权
|
7月前
|
数据挖掘 Java 测试技术
无代码动态表单系统 毕业设计 JAVA+Vue+SpringBoot+MySQL(一)
无代码动态表单系统 毕业设计 JAVA+Vue+SpringBoot+MySQL
|
3月前
|
存储 Java 关系型数据库
springboot整合多数据源的配置以及动态切换数据源,注解切换数据源
springboot整合多数据源的配置以及动态切换数据源,注解切换数据源
76 0
|
9月前
|
人工智能 监控 Java
SpringBoot实战(十三):Spring Boot Admin 动态修改日志级别
SpringBoot实战(十三):Spring Boot Admin 动态修改日志级别
346 0
|
4月前
|
Java 数据库连接 数据库
【Spring技术专题】「实战开发系列」保姆级教你SpringBoot整合Mybatis框架实现多数据源的静态数据源和动态数据源配置落地
Mybatis是一个基于JDBC实现的,支持普通 SQL 查询、存储过程和高级映射的优秀持久层框架,去掉了几乎所有的 JDBC 代码和参数的手工设置以及对结果集的检索封装。 Mybatis主要思想是将程序中大量的 SQL 语句剥离出来,配置在配置文件中,以实现 SQL 的灵活配置。在所有 ORM 框架中都有一个非常重要的媒介——PO(持久化对象),PO 的作用就是完成持久化操作,通过该对象对数据库执行增删改的操作,以面向对象的方式操作数据库。
46 1
【Spring技术专题】「实战开发系列」保姆级教你SpringBoot整合Mybatis框架实现多数据源的静态数据源和动态数据源配置落地
|
4月前
|
安全 JavaScript Java
你有没有觉得邮件发送人固定配置在yml文件中是不妥当的呢?SpringBoot 动态设置邮件发送人
你有没有觉得邮件发送人固定配置在yml文件中是不妥当的呢?SpringBoot 动态设置邮件发送人
58 0
|
4月前
|
Java 程序员 数据库
SpringBoot实现固定、动态定时任务 | 三种实现方式
SpringBoot实现固定、动态定时任务 | 三种实现方式
107 0
|
5月前
|
Java
SpringBoot原理分析 | 任务:异步、邮件、定时
SpringBoot原理分析 | 任务:异步、邮件、定时
66 0