广告位联系
返回顶部
分享到

SpringBoot实现动态添加定时任务功能

java 来源:互联网 作者:秩名 发布时间:2022-02-28 14:32:45 人浏览
摘要

最近的需求有一个自动发布的功能, 需要做到每次提交都要动态的添加一个定时任务 代码结构 1. 配置类 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 package com.orion.ops.config; impo

最近的需求有一个自动发布的功能, 需要做到每次提交都要动态的添加一个定时任务

代码结构

1. 配置类

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

package com.orion.ops.config;

  

import org.springframework.context.annotation.Bean;

import org.springframework.context.annotation.Configuration;

import org.springframework.scheduling.TaskScheduler;

import org.springframework.scheduling.annotation.EnableScheduling;

import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler;

/**

 * 调度器配置

 *

 * @author Jiahang Li

 * @version 1.0.0

 * @since 2022/2/14 9:51

 */

@EnableScheduling

@Configuration

public class SchedulerConfig {

    @Bean

    public TaskScheduler taskScheduler() {

        ThreadPoolTaskScheduler scheduler = new ThreadPoolTaskScheduler();

        scheduler.setPoolSize(4);

        scheduler.setRemoveOnCancelPolicy(true);

        scheduler.setThreadNamePrefix("scheduling-task-");

        return scheduler;

    }

}

2. 定时任务类型枚举

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

package com.orion.ops.handler.scheduler;

  

import com.orion.ops.consts.Const;

import com.orion.ops.handler.scheduler.impl.ReleaseTaskImpl;

import com.orion.ops.handler.scheduler.impl.SchedulerTaskImpl;

import lombok.AllArgsConstructor;

import java.util.function.Function;

/**

 * 任务类型

 *

 * @author Jiahang Li

 * @version 1.0.0

 * @since 2022/2/14 10:16

 */

@AllArgsConstructor

public enum TaskType {

    /**

     * 发布任务

     */

    RELEASE(id -> new ReleaseTaskImpl((Long) id)) {

        @Override

        public String getKey(Object params) {

            return Const.RELEASE + "-" + params;

        }

    },

     * 调度任务

    SCHEDULER_TASK(id -> new SchedulerTaskImpl((Long) id)) {

            return Const.TASK + "-" + params;

    ;

    private final Function<Object, Runnable> factory;

     * 创建任务

     *

     * @param params params

     * @return task

    public Runnable create(Object params) {

        return factory.apply(params);

    }

     * 获取 key

     * @return key

    public abstract String getKey(Object params);

}

这个枚举的作用是生成定时任务的 runnable 和 定时任务的唯一值, 方便后续维护

3. 实际执行任务实现类

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

package com.orion.ops.handler.scheduler.impl;

  

import com.orion.ops.service.api.ApplicationReleaseService;

import com.orion.spring.SpringHolder;

import lombok.extern.slf4j.Slf4j;

/**

 * 发布任务实现

 *

 * @author Jiahang Li

 * @version 1.0.0

 * @since 2022/2/14 10:25

 */

@Slf4j

public class ReleaseTaskImpl implements Runnable {

    protected static ApplicationReleaseService applicationReleaseService = SpringHolder.getBean(ApplicationReleaseService.class);

    private Long releaseId;

    public ReleaseTaskImpl(Long releaseId) {

        this.releaseId = releaseId;

    }

    @Override

    public void run() {

        log.info("定时执行发布任务-触发 releaseId: {}", releaseId);

        applicationReleaseService.runnableAppRelease(releaseId, true);

}

4. 定时任务包装器

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

package com.orion.ops.handler.scheduler;

  

import org.springframework.scheduling.TaskScheduler;

import org.springframework.scheduling.Trigger;

import java.util.Date;

import java.util.concurrent.ScheduledFuture;

/**

 * 定时 任务包装器

 *

 * @author Jiahang Li

 * @version 1.0.0

 * @since 2022/2/14 10:34

 */

public class TimedTask {

    /**

     * 任务

     */

    private Runnable runnable;

     * 异步执行

    private volatile ScheduledFuture<?> future;

    public TimedTask(Runnable runnable) {

        this.runnable = runnable;

    }

     * 提交任务 一次性

     *

     * @param scheduler scheduler

     * @param time      time

    public void submit(TaskScheduler scheduler, Date time) {

        this.future = scheduler.schedule(runnable, time);

     * 提交任务 cron表达式

     * @param trigger   trigger

    public void submit(TaskScheduler scheduler, Trigger trigger) {

        this.future = scheduler.schedule(runnable, trigger);

     * 取消定时任务

    public void cancel() {

        if (future != null) {

            future.cancel(true);

        }

}

这个类的作用是包装实际执行任务, 以及提供调度器的执行方法

5. 任务注册器 (核心)

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

package com.orion.ops.handler.scheduler;

  

import com.orion.ops.consts.MessageConst;

import com.orion.utils.Exceptions;

import com.orion.utils.collect.Maps;

import org.springframework.beans.factory.DisposableBean;

import org.springframework.beans.factory.annotation.Qualifier;

import org.springframework.scheduling.TaskScheduler;

import org.springframework.scheduling.support.CronTrigger;

import org.springframework.stereotype.Component;

import javax.annotation.Resource;

import java.util.Date;

import java.util.Map;

/**

 * 任务注册器

 *

 * @author Jiahang Li

 * @version 1.0.0

 * @since 2022/2/14 10:46

 */

@Component

public class TaskRegister implements DisposableBean {

    private final Map<String, TimedTask> taskMap = Maps.newCurrentHashMap();

    @Resource

    @Qualifier("taskScheduler")

    private TaskScheduler scheduler;

    /**

     * 提交任务

     *

     * @param type   type

     * @param time   time

     * @param params params

     */

    public void submit(TaskType type, Date time, Object params) {

        // 获取任务

        TimedTask timedTask = this.getTask(type, params);

        // 执行任务

        timedTask.submit(scheduler, time);

    }

     * @param cron   cron

    public void submit(TaskType type, String cron, Object params) {

        timedTask.submit(scheduler, new CronTrigger(cron));

     * 获取任务

    private TimedTask getTask(TaskType type, Object params) {

        // 生成任务

        Runnable runnable = type.create(params);

        String key = type.getKey(params);

        // 判断是否存在任务

        if (taskMap.containsKey(key)) {

            throw Exceptions.init(MessageConst.TASK_PRESENT);

        }

        TimedTask timedTask = new TimedTask(runnable);

        taskMap.put(key, timedTask);

        return timedTask;

     * 取消任务

    public void cancel(TaskType type, Object params) {

        TimedTask task = taskMap.get(key);

        if (task != null) {

            taskMap.remove(key);

            task.cancel();

     * 是否存在

    public boolean has(TaskType type, Object params) {

        return taskMap.containsKey(type.getKey(params));

    @Override

    public void destroy() {

        taskMap.values().forEach(TimedTask::cancel);

        taskMap.clear();

}

这个类提供了执行, 提交任务的api, 实现 DisposableBean 接口, 便于在bean销毁时将任务一起销毁

6. 使用

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

@Resource

private TaskRegister taskRegister;

 

/**

 * 提交发布

 */

@RequestMapping("/submit")

@EventLog(EventType.SUBMIT_RELEASE)

public Long submitAppRelease(@RequestBody ApplicationReleaseRequest request) {

    Valid.notBlank(request.getTitle());

    Valid.notNull(request.getAppId());

    Valid.notNull(request.getProfileId());

    Valid.notNull(request.getBuildId());

    Valid.notEmpty(request.getMachineIdList());

    TimedReleaseType timedReleaseType = Valid.notNull(TimedReleaseType.of(request.getTimedRelease()));

    if (TimedReleaseType.TIMED.equals(timedReleaseType)) {

        Date timedReleaseTime = Valid.notNull(request.getTimedReleaseTime());

        Valid.isTrue(timedReleaseTime.compareTo(new Date()) > 0, MessageConst.TIMED_GREATER_THAN_NOW);

    }

    // 提交

    Long id = applicationReleaseService.submitAppRelease(request);

    // 提交任务

        taskRegister.submit(TaskType.RELEASE, request.getTimedReleaseTime(), id);

    return id;

}

最后

       这是一个简单的动态添加定时任务的工具, 有很多的改造空间, 比如想持久化可以插入到库中, 定义一个 CommandLineRunner 在启动时将定时任务全部加载, 还可以给任务加钩子自动提交,自动删除等, 代码直接cv一定会报错, 就是一些工具, 常量类会报错, 改改就好了, 本人已亲测可用, 有什么问题可以在评论区沟通


版权声明 : 本文内容来源于互联网或用户自行发布贡献,该文观点仅代表原作者本人。本站仅提供信息存储空间服务和不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权, 违法违规的内容, 请发送邮件至2530232025#qq.cn(#换@)举报,一经查实,本站将立刻删除。
原文链接 : https://blog.csdn.net/qq_41011894/article/details/123116277
相关文章
  • SpringBoot自定义错误处理逻辑介绍

    SpringBoot自定义错误处理逻辑介绍
    1. 自定义错误页面 将自定义错误页面放在 templates 的 error 文件夹下,SpringBoot 精确匹配错误信息,使用 4xx.html 或者 5xx.html 页面可以打印错误
  • Java实现手写一个线程池的代码

    Java实现手写一个线程池的代码
    线程池技术想必大家都不陌生把,相信在平时的工作中没有少用,而且这也是面试频率非常高的一个知识点,那么大家知道它的实现原理和
  • Java实现断点续传功能的代码

    Java实现断点续传功能的代码
    题目实现:网络资源的断点续传功能。 二、解题思路 获取要下载的资源网址 显示网络资源的大小 上次读取到的字节位置以及未读取的字节
  • 你可知HashMap为什么是线程不安全的
    HashMap 的线程不安全 HashMap 的线程不安全主要体现在下面两个方面 在 jdk 1.7 中,当并发执行扩容操作时会造成环形链和数据丢失的情况 在
  • ArrayList的动态扩容机制的介绍

    ArrayList的动态扩容机制的介绍
    对于 ArrayList 的动态扩容机制想必大家都听说过,之前的文章中也谈到过,不过由于时间久远,早已忘却。 所以利用这篇文章做做笔记,加
  • JVM基础之字节码的增强技术介绍

    JVM基础之字节码的增强技术介绍
    字节码增强技术 在上文中,着重介绍了字节码的结构,这为我们了解字节码增强技术的实现打下了基础。字节码增强技术就是一类对现有字
  • Java中的字节码增强技术

    Java中的字节码增强技术
    1.字节码增强技术 字节码增强技术就是一类对现有字节码进行修改或者动态生成全新字节码文件的技术。 参考地址 2.常见技术 技术分类 类
  • Redis BloomFilter布隆过滤器原理与实现

    Redis BloomFilter布隆过滤器原理与实现
    Bloom Filter 概念 布隆过滤器(英语:Bloom Filter)是1970年由一个叫布隆的小伙子提出的。它实际上是一个很长的二进制向量和一系列随机映射
  • Java C++算法题解leetcode801使序列递增的最小交换次

    Java C++算法题解leetcode801使序列递增的最小交换次
    题目要求 思路:状态机DP 实现一:状态机 Java 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 class Solution { public int minSwap(int[] nums1, int[] nums2) { int n
  • Mybatis结果集映射与生命周期介绍

    Mybatis结果集映射与生命周期介绍
    一、ResultMap结果集映射 1、设计思想 对简单的语句做到零配置,对于复杂一点的语句,只需要描述语句之间的关系就行了 2、resultMap的应用场
  • 本站所有内容来源于互联网或用户自行发布,本站仅提供信息存储空间服务,不拥有版权,不承担法律责任。如有侵犯您的权益,请您联系站长处理!
  • Copyright © 2017-2022 F11.CN All Rights Reserved. F11站长开发者网 版权所有 | 苏ICP备2022031554号-1 | 51LA统计