千家信息网

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

发表于:2025-01-18 作者:千家信息网编辑
千家信息网最后更新 2025年01月18日,这篇"怎么用SpringBoot实现动态添加定时任务功能"文章的知识点大部分人都不太理解,所以小编给大家总结了以下内容,内容详细,步骤清晰,具有一定的借鉴价值,希望大家阅读完这篇文章能有所收获,下面我
千家信息网最后更新 2025年01月18日怎么用SpringBoot实现动态添加定时任务功能

这篇"怎么用SpringBoot实现动态添加定时任务功能"文章的知识点大部分人都不太理解,所以小编给大家总结了以下内容,内容详细,步骤清晰,具有一定的借鉴价值,希望大家阅读完这篇文章能有所收获,下面我们一起来看看这篇"怎么用SpringBoot实现动态添加定时任务功能"文章吧。

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

代码结构

1. 配置类

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@Configurationpublic class SchedulerConfig {    @Bean    public TaskScheduler taskScheduler() {        ThreadPoolTaskScheduler scheduler = new ThreadPoolTaskScheduler();        scheduler.setPoolSize(4);        scheduler.setRemoveOnCancelPolicy(true);        scheduler.setThreadNamePrefix("scheduling-task-");        return scheduler;    }}

2. 定时任务类型枚举

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 */@AllArgsConstructorpublic 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 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. 实际执行任务实现类

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 */@Slf4jpublic 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. 定时任务包装器

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. 任务注册器 (核心)

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 */@Componentpublic class TaskRegister implements DisposableBean {    private final Map 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. 使用

    @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;    }

以上就是关于"怎么用SpringBoot实现动态添加定时任务功能"这篇文章的内容,相信大家都有了一定的了解,希望小编分享的内容对大家有帮助,若想了解更多相关的知识内容,请关注行业资讯频道。

0