mldong 快速开发框架定时任务模块设计与实现

196 阅读4分钟

mldong 快速开发框架是一款基于 Spring Boot 的高效开发工具,其中的定时任务模块是其核心功能之一。本文将详细介绍该模块的设计理念、架构组成以及关键代码实现,并结合前端页面截图展示其实际应用效果。


一、模块概述

定时任务模块旨在提供一个灵活、可扩展的调度机制,支持动态配置任务执行周期、状态管理及任务立即执行等功能。通过集成 Redis 锁机制,确保了分布式环境下的任务调度一致性,避免重复执行问题。

主要功能:

  • 定时任务注册与启动
  • 任务状态管理(运行/停止)
  • 任务调度表达式动态修改
  • 任务立即执行
  • 任务信息缓存与持久化

二、架构设计

整个模块采用接口驱动 + 注解增强 + AOP 切面 + 缓存管理的方式构建,主要包括以下几个核心组件:

1. TimerTaskRunner 接口

所有定时任务类必须实现此接口,定义如下:

public interface TimerTaskRunner {
    void action();
    String getCron();
    boolean isXxlJob();
    String getName();
}

示例:RefreshConstantsTaskRunner 实现了该接口,用于刷新常量缓存。

2. @TimerLock 注解与切面

通过 @TimerLock 注解对任务方法加锁,防止并发执行:

@Aspect
@Component
@Order(120)
@Slf4j
public class TimerLockAop {
    @Around("@annotation(timerLock)")
    public void doAction(ProceedingJoinPoint proceedingJoinPoint, TimerLock timerLock) throws Throwable {
        boolean enable = RedisUtil.lock("TimerLock:" + timerLock.name(), StrUtil.uuid(), timerLock.autoReleaseTime(), timerLock.timeUnit());
        if (enable) {
            proceedingJoinPoint.proceed();
        }
    }

    @AfterThrowing("@annotation(timerLock)")
    @After("@annotation(timerLock)")
    public void doActionAfter(TimerLock timerLock) {
        RedisUtil.releaseLock("TimerLock:" + timerLock.name());
    }
}

3. TimerCache 缓存管理

继承自 AbstractRedisCacheOperator<TimerModel>,负责任务模型在 Redis 中的缓存操作。

public class TimerCache extends AbstractRedisCacheOperator<TimerModel> {
    public TimerCache(RedisTemplate<String, TimerModel> redisTemplate) {
        super(redisTemplate);
    }

    @Override
    public String getCommonKeyPrefix() {
        return "timers:";
    }
}

4. TimerModel 模型

封装任务元数据,包括任务名称、执行类、cron 表达式、状态等。

@Data
public class TimerModel implements Serializable {
    private String id;
    private String timerName;
    private String actionClass;
    private String cron;
    private String redisCron;
    private Integer state;
    private String remark;

    public TimerModel build(TimerTaskRunner timerTaskRunner) {
        this.setTimerName(timerTaskRunner.getClass().getSimpleName());
        this.setActionClass(timerTaskRunner.getClass().getName());
        this.setCron(timerTaskRunner.getCron());
        this.setRedisCron(timerTaskRunner.getCron());
        this.setState(TimerStateEnum.RUNNING.getCode());
        this.setRemark(timerTaskRunner.getName());
        return this;
    }
}

5. TimerTaskRunListener 启动监听器

项目启动时加载所有 TimerTaskRunner 实现类,并初始化定时任务。

public class TimerTaskRunListener implements ApplicationListener<ApplicationStartedEvent>, Ordered {
    @Override
    public void onApplicationEvent(ApplicationStartedEvent event) {
        TimerCache timerCache = SpringUtil.getBean(TimerCache.class);
        Map<String, TimerTaskRunner> timerTaskRunnerMap = SpringUtil.getBeansOfType(TimerTaskRunner.class);

        timerTaskRunnerMap.forEach((name, timerTaskRunner) -> {
            if (!timerTaskRunner.isXxlJob() && StrUtil.isNotEmpty(timerTaskRunner.getCron())) {
                TimerModel timerModel = timerCache.get(timerTaskRunner.getClass().getSimpleName());
                if (timerModel == null) {
                    timerModel = new TimerModel().build(timerTaskRunner);
                } else {
                    timerModel.setCron(timerTaskRunner.getCron());
                }
                timerCache.put(timerTaskRunner.getClass().getSimpleName(), timerModel);

                if (ObjectUtil.equals(timerModel.getState(), TimerStateEnum.RUNNING.getCode())) {
                    Task task = timerTaskRunner::action;
                    CronUtil.schedule(timerModel.getId(), timerModel.getRedisCron(), task);
                }
            }
        });

        CronUtil.setMatchSecond(true);
        CronUtil.start();
    }

    @Override
    public int getOrder() {
        return LOWEST_PRECEDENCE;
    }
}

三、控制层设计

TimerController 提供 RESTful API 接口,用于任务的启停、修改、查询等操作。

@RestController
@Api(tags = "定时任务管理")
@RequiredArgsConstructor
public class TimerController {
    private final TimerService timerService;

    @PostMapping("/sys/timer/stop")
    @ApiOperation(value = "停止定时任务")
    @SaCheckPermission("sys:timer:stop")
    public CommonResult<?> stop(@RequestBody Dict param) {
        timerService.stop(param.get("id", param.getStr("name")));
        return CommonResult.ok();
    }

    @PostMapping("/sys/timer/start")
    @ApiOperation(value = "开始定时任务")
    @SaCheckPermission("sys:timer:start")
    public CommonResult<?> start(@RequestBody Dict param) {
        timerService.start(param.get("id", param.getStr("name")));
        return CommonResult.ok();
    }

    // 其他接口略...
}

四、服务层实现

TimerServiceImplTimerService 接口的具体实现类,负责调用底层 Hutool Cron 工具和 Redis 缓存。

@Service
@RequiredArgsConstructor
public class TimerServiceImpl implements TimerService {
    private final Map<String, TimerTaskRunner> timerTaskRunnerMap;
    private final TimerCache timerCache;

    @Override
    public void stop(String name) {
        TimerTaskRunner timerTaskRunner = getTimerTaskRunner(name);
        if (timerTaskRunner == null) return;
        String timerId = timerTaskRunner.getClass().getSimpleName();
        CronUtil.remove(timerId);
        TimerModel timerModel = timerCache.get(timerId);
        if (timerModel != null) {
            timerModel.setState(TimerStateEnum.STOP.getCode());
            timerCache.put(timerModel.getId(), timerModel);
        }
    }

    @Override
    public void start(String name) {
        Task task = CronUtil.getScheduler().getTask(name);
        TimerTaskRunner timerTaskRunner = getTimerTaskRunner(name);
        if (task == null && timerTaskRunner != null) {
            TimerModel timerModel = timerCache.get(timerTaskRunner.getClass().getSimpleName());
            if (timerModel == null) {
                timerModel = new TimerModel().build(timerTaskRunner);
            } else {
                timerModel.setState(TimerStateEnum.RUNNING.getCode());
                timerCache.put(timerModel.getId(), timerModel);
            }
            task = timerTaskRunner::action;
            CronUtil.schedule(timerModel.getId(), timerModel.getRedisCron(), task);
        }
    }

    // 其他方法略...
}

五、前端功能展示

以下为定时任务模块在前端管理系统的界面截图及说明:

1. 定时任务列表页

【系统设置】->【定时任务】

转存失败,建议直接上传图片文件

  • 功能点
    • 分页显示所有定时任务;
    • 支持按关键词搜索、按状态筛选;
    • 显示字段:
      • 执行类名
      • 默认cron表达式
      • 当前cron表达式
      • 状态
      • 备注;
    • 操作按钮:
      • 详情
      • 编辑
      • 执行
      • 停止
      • 重置。

2. 定时任务详情页

  • 功能点
    • 查看任务详细信息;
    • 包括
      • 唯一编码
      • 执行类名
      • 状态
      • 默认cron表达式
      • 当前cron表达式
      • 备注;

3. 定时任务编辑页

  • 功能点
    • 仅停止状态下才可以修改表达式
    • 修改任务的备注信息;
    • 修改 Redis 中存储的 cron 表达式;
    • 校验 cron 表达式合法性;
    • 点击“保存”更新缓存与数据库。

4. 立即执行任务

  • 功能点
    • 点击“执行”后触发后台任务;
    • 前端提示执行成功。

5. 任务状态切换对比图

  • 功能点
    • 点击“停止”后,任务状态变为“停止”;
    • 再次点击“启动”,状态变回“运行”;
    • 支持批量重置任务配置。

六、总结

mldong 定时任务模块通过良好的分层设计、注解增强、AOP 切面和缓存机制,实现了任务的动态管理与高可用性。开发者只需实现 TimerTaskRunner 接口并添加相应注解即可快速接入定时任务系统,极大地提升了开发效率与系统稳定性。

如需获取完整源码,请访问 Gitee 地址:

🔗 gitee.com/mldong/mldo…