Skip to content

DynamicTaskScheduler 动态定时任务调度器使用文档 ​

一、概述 ​

DynamicTaskScheduler 是一个基于 Spring 的动态定时任务调度器,支持运行时动态添加、更新和删除定时任务。它使用 Cron 表达式实现灵活的任务调度,适用于需要动态管理定时任务的业务场景。

核心特性 ​

  • 动态任务管理: 支持运行时添加、更新、删除定时任务
  • 多种执行模式: 支持单次执行、定时执行(按周、按月、按季度)
  • Cron 表达式生成: 自动根据业务参数生成标准 Cron 表达式
  • 线程安全: 基于 ConcurrentHashMap 实现,支持并发操作
  • 下次执行时间计算: 自动计算并返回任务的下次执行时间
  • 任务取消: 支持优雅地取消正在运行或待执行的任务

二、快速开始 ​

2.1 基本使用 ​

java
@Service
public class ReportTaskService {

    @Resource
    private DynamicTaskScheduler dynamicTaskScheduler;

    @Resource
    private AuditReportService auditReportService;

    /**
     * 创建定时任务
     */
    public LocalDateTime createTask() {
        // 1. 准备任务配置
        TimingTaskBaseDTO task = new TimingTaskBaseDTO();
        task.setTaskName("audit_report_task_001");     // 任务名称(唯一标识)
        task.setExecuteType("2");                       // 执行类型:2=定时执行
        task.setPeriodType("1");                        // 周期类型:1=按月
        task.setPeriodVal("15");                        // 周期值:每月15号

        // 2. 创建任务执行器
        Runnable taskRunnable = new AuditReportTaskRunnable(
            auditReportService,
            taskConfigId
        );

        // 3. 调度任务,返回下次执行时间
        LocalDateTime nextExecuteTime = dynamicTaskScheduler.scheduleTask(task, taskRunnable);

        System.out.println("任务已创建,下次执行时间: " + nextExecuteTime);
        return nextExecuteTime;
    }
}

2.2 创建任务执行器 ​

java
/**
 * 审计报告定时任务执行器
 */
public class AuditReportTaskRunnable implements Runnable {

    private final Long taskConfigId;
    private final AuditReportService auditReportService;

    public AuditReportTaskRunnable(AuditReportService auditReportService, Long taskConfigId) {
        this.taskConfigId = taskConfigId;
        this.auditReportService = auditReportService;
    }

    @Override
    public void run() {
        try {
            // 执行业务逻辑
            auditReportService.generateReport(taskConfigId);
        } catch (Exception e) {
            // 异常处理
            log.error("定时任务执行失败: taskConfigId={}", taskConfigId, e);
        }
    }
}

三、任务配置详解 ​

3.1 TimingTaskBaseDTO 参数说明 ​

java
@Data
public class TimingTaskBaseDTO {

    /**
     * 任务名称(必填)
     * 作为任务的唯一标识,用于后续更新、删除操作
     */
    private String taskName;

    /**
     * 执行类型(必填)
     * - "1": 单次执行 - 在指定时间执行一次后自动停止
     * - "2": 定时执行 - 按照周期规则持续执行
     */
    private String executeType;

    /**
     * 执行时间(单次执行时必填)
     * 指定任务的执行时间点
     */
    private LocalDateTime executeDate;

    /**
     * 周期类型(定时执行时必填)
     * - "0": 按周执行
     * - "1": 按月执行
     * - "2": 按季度执行
     */
    private String periodType;

    /**
     * 周期值(定时执行时必填)
     * 格式根据周期类型不同而不同,详见下文
     */
    private String periodVal;
}

3.2 执行类型说明 ​

3.2.1 单次执行 (executeType = "1") ​

任务在指定时间执行一次后自动停止。

示例:在 2024年12月31日 23:59 执行一次

java
TimingTaskBaseDTO task = new TimingTaskBaseDTO();
task.setTaskName("year_end_report");
task.setExecuteType("1");
task.setExecuteDate(LocalDateTime.of(2024, 12, 31, 23, 59, 0));

// 生成的Cron表达式: 0 59 23 31 12 ?

生成的 Cron 表达式格式:

0 [分钟] [小时] [日期] [月份] ?

3.2.2 定时执行 (executeType = "2") ​

任务按照指定的周期规则持续执行。

需要配置:

  • periodType: 周期类型
  • periodVal: 周期值

3.3 周期类型详解 ​

3.3.1 按周执行 (periodType = "0") ​

周期值格式: 1-7 (数字,表示星期几)

  • 1 = 星期一
  • 2 = 星期二
  • 3 = 星期三
  • 4 = 星期四
  • 5 = 星期五
  • 6 = 星期六
  • 7 = 星期日

示例1:每周一执行

java
task.setExecuteType("2");
task.setPeriodType("0");
task.setPeriodVal("1");

// 生成的Cron表达式: 0 0 0 * * 1
// 含义: 每周一 00:00:00 执行

示例2:每周五执行

java
task.setPeriodType("0");
task.setPeriodVal("5");

// 生成的Cron表达式: 0 0 0 * * 5
// 含义: 每周五 00:00:00 执行

3.3.2 按月执行 (periodType = "1") ​

周期值格式: 1-31 (数字,表示月份中的日期)

示例1:每月15号执行

java
task.setExecuteType("2");
task.setPeriodType("1");
task.setPeriodVal("15");

// 生成的Cron表达式: 0 0 0 15 * ?
// 含义: 每月15号 00:00:00 执行

示例2:每月1号执行(月初报表)

java
task.setPeriodType("1");
task.setPeriodVal("1");

// 生成的Cron表达式: 0 0 0 1 * ?
// 含义: 每月1号 00:00:00 执行

示例3:每月最后一天执行

java
task.setPeriodType("1");
task.setPeriodVal("31");

// 注意:对于只有30天的月份,会在30号执行
// 对于2月,会在28或29号执行

3.3.3 按季度执行 (periodType = "2") ​

周期值格式: 季度中的月份,日期

  • 季度中的月份: 1-3 (1=季度第一个月, 2=季度第二个月, 3=季度第三个月)
  • 日期: 1-31

季度划分:

  • 第一季度: 1月、2月、3月
  • 第二季度: 4月、5月、6月
  • 第三季度: 7月、8月、9月
  • 第四季度: 10月、11月、12月

示例1:每季度首月15号执行

java
task.setExecuteType("2");
task.setPeriodType("2");
task.setPeriodVal("1,15");

// 生成的Cron表达式: 0 0 0 15 1,4,7,10 ?
// 含义: 1月15日、4月15日、7月15日、10月15日 00:00:00 执行

示例2:每季度末月最后一天执行

java
task.setPeriodType("2");
task.setPeriodVal("3,31");

// 生成的Cron表达式: 0 0 0 31 3,6,9,12 ?
// 含义: 3月31日、6月30日、9月30日、12月31日 执行

示例3:每季度第二个月10号执行

java
task.setPeriodType("2");
task.setPeriodVal("2,10");

// 生成的Cron表达式: 0 0 0 10 2,5,8,11 ?
// 含义: 2月10日、5月10日、8月10日、11月10日 00:00:00 执行

四、完整使用案例 ​

4.1 审计报告定时任务管理 ​

以 AuditReportTaskConfigServiceImpl 为例,展示完整的任务管理流程。

4.1.1 创建任务 ​

java
@Service
public class AuditReportTaskConfigServiceImpl implements AuditReportTaskConfigService {

    @Resource
    private DynamicTaskScheduler dynamicTaskScheduler;

    @Resource
    private AuditReportService auditReportService;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean saveTaskConfig(AuditReportTaskConfigEntity taskConfig) {
        // 1. 保存任务配置到数据库
        save(taskConfig);

        // 2. 启动定时任务
        startTask(taskConfig);

        return true;
    }

    /**
     * 启动定时任务
     */
    private void startTask(AuditReportTaskConfigEntity taskConfig) {
        // 构建任务名称
        String taskName = "AUDIT_REPORT_TASK_" + taskConfig.getTaskName();

        // 获取任务配置参数
        String executeType = taskConfig.getExecuteType();
        LocalDateTime executeDate = taskConfig.getExecuteDate();
        String periodType = taskConfig.getPeriodType();
        String periodVal = taskConfig.getPeriodVal();

        // 创建任务DTO
        TimingTaskBaseDTO task = new TimingTaskBaseDTO(
            taskName,
            executeType,
            executeDate,
            periodType,
            periodVal
        );

        // 只有单次执行或定时执行才启动任务
        if ("1".equals(executeType) || "2".equals(executeType)) {
            // 创建任务执行器
            AuditReportTaskRunnable runnable = new AuditReportTaskRunnable(
                auditReportService,
                taskConfig.getId()
            );

            // 调度任务并获取下次执行时间
            LocalDateTime nextExecuteTime = dynamicTaskScheduler.scheduleTask(task, runnable);

            // 保存下次执行时间
            taskConfig.setNextTaskDate(nextExecuteTime);
            updateById(taskConfig);

            log.info("定时任务已启动: taskName={}, nextExecuteTime={}",
                    taskName, nextExecuteTime);
        }
    }
}

4.1.2 更新任务 ​

java
@Override
@Transactional(rollbackFor = Exception.class)
public Boolean updateTaskConfig(AuditReportTaskConfigEntity taskConfig) {
    // 1. 更新数据库
    updateById(taskConfig);

    // 2. 根据任务状态决定启动或关闭
    if ("1".equals(taskConfig.getTaskStatus())) {
        // 任务状态为开启,先取消旧任务再启动新任务
        startTask(taskConfig);
    } else {
        // 任务状态为关闭,取消任务
        closeTask(taskConfig);
    }

    return true;
}

/**
 * 关闭任务
 */
private void closeTask(AuditReportTaskConfigEntity taskConfig) {
    String taskName = "AUDIT_REPORT_TASK_" + taskConfig.getTaskName();

    TimingTaskBaseDTO task = new TimingTaskBaseDTO();
    task.setTaskName(taskName);

    // 取消任务
    dynamicTaskScheduler.removeTask(task);

    log.info("定时任务已关闭: taskName={}", taskName);
}

4.1.3 删除任务 ​

java
@Override
public Boolean deleteTask(Long id) {
    // 1. 获取任务配置
    AuditReportTaskConfigEntity taskConfig = getById(id);

    // 2. 关闭定时任务
    closeTask(taskConfig);

    // 3. 删除数据库记录
    removeById(id);

    return true;
}

4.1.4 提醒任务(复杂场景) ​

java
/**
 * 启动提醒任务
 * 在主任务执行前一定时间发送提醒通知
 */
private void startRemindTask(AuditReportTaskConfigEntity taskConfig) {
    // 1. 计算提醒时间
    LocalDateTime remindDateTime = calculateRemindTime(taskConfig);

    // 2. 创建提醒任务
    String remindTaskName = taskConfig.getTaskName() + "_REMIND";
    TimingTaskBaseDTO remindTask = new TimingTaskBaseDTO();
    remindTask.setTaskName(remindTaskName);
    remindTask.setExecuteType("1");  // 单次执行
    remindTask.setExecuteDate(remindDateTime);

    // 3. 创建提醒任务执行器
    AuditReportTaskRemindRunnable runnable = new AuditReportTaskRemindRunnable(
        remindTask,
        dynamicTaskScheduler
    );

    // 4. 调度提醒任务
    dynamicTaskScheduler.scheduleTask(remindTask, runnable);

    log.info("提醒任务已启动: taskName={}, remindTime={}",
            remindTaskName, remindDateTime);
}

/**
 * 计算提醒时间
 */
private LocalDateTime calculateRemindTime(AuditReportTaskConfigEntity taskConfig) {
    LocalDate taskDate = taskConfig.getNextTaskDate().toLocalDate();
    LocalDate now = LocalDate.now();
    Period period = Period.between(now, taskDate);
    int days = period.getDays();

    LocalDate remindDate;
    if (days >= 180) {
        // 距离执行时间>=180天,提前30天提醒
        remindDate = taskDate.minusDays(30);
    } else if (days >= 30) {
        // 距离执行时间>=30天,提前7天提醒
        remindDate = taskDate.minusDays(7);
    } else {
        // 距离执行时间<30天,提前2天提醒
        remindDate = taskDate.minusDays(2);
    }

    // 设置提醒时间为下午3点
    return remindDate.atTime(15, 0, 0);
}

4.2 应用启动时自动加载任务 ​

java
@Component
public class TaskInitializer {

    @Resource
    private DynamicTaskScheduler dynamicTaskScheduler;

    @Resource
    private AuditReportTaskConfigService reportTaskConfigService;

    @Resource
    private AuditReportService auditReportService;

    /**
     * 应用启动后自动加载所有开启状态的任务
     */
    @PostConstruct
    public void initEnabledTasks() {
        // 1. 查询所有开启状态的任务
        List<AuditReportTaskConfigEntity> reportList =
            reportTaskConfigService.getOpenStatusTask();

        // 2. 逐个启动任务
        reportList.forEach(taskConfig -> {
            String taskName = "AUDIT_REPORT_TASK_" + taskConfig.getTaskName();
            String executeType = taskConfig.getExecuteType();

            // 只启动单次执行和定时执行的任务
            if ("1".equals(executeType) || "2".equals(executeType)) {
                // 创建任务DTO
                TimingTaskBaseDTO task = new TimingTaskBaseDTO(
                    taskName,
                    executeType,
                    taskConfig.getExecuteDate(),
                    taskConfig.getPeriodType(),
                    taskConfig.getPeriodVal()
                );

                // 创建任务执行器
                AuditReportTaskRunnable runnable = new AuditReportTaskRunnable(
                    auditReportService,
                    taskConfig.getId()
                );

                // 调度任务
                dynamicTaskScheduler.scheduleTask(task, runnable);

                // 更新关联数据
                reportTaskConfigService.uploadReportLinkData(taskConfig.getId());

                log.info("已加载定时任务: {}", taskName);
            }
        });

        log.info("定时任务初始化完成,共加载 {} 个任务", reportList.size());
    }
}

五、高级功能 ​

5.1 计算下次执行时间 ​

java
@Service
public class TaskScheduleService {

    @Resource
    private DynamicTaskScheduler dynamicTaskScheduler;

    /**
     * 获取任务的下次执行时间
     */
    public LocalDateTime getNextExecuteTime(AuditReportTaskConfigEntity taskConfig) {
        // 生成Cron表达式
        String cronExpression = DynamicTaskScheduler.generateCronExpression(
            taskConfig.getExecuteType(),
            taskConfig.getExecuteDate(),
            taskConfig.getPeriodType(),
            taskConfig.getPeriodVal()
        );

        if (cronExpression == null) {
            return null;
        }

        // 计算下次执行时间
        return dynamicTaskScheduler.getCronByData(cronExpression);
    }
}

5.2 手动生成 Cron 表达式 ​

java
// 按周执行:每周三
String cron1 = DynamicTaskScheduler.generateCronExpression(
    "2",                        // 定时执行
    null,                       // 无需执行时间
    "0",                        // 按周
    "3"                         // 周三
);
System.out.println(cron1);  // 输出: 0 0 0 * * 3

// 按月执行:每月10号
String cron2 = DynamicTaskScheduler.generateCronExpression(
    "2",                        // 定时执行
    null,
    "1",                        // 按月
    "10"                        // 10号
);
System.out.println(cron2);  // 输出: 0 0 0 10 * ?

// 单次执行:2024年6月30日 18:00
LocalDateTime executeTime = LocalDateTime.of(2024, 6, 30, 18, 0, 0);
String cron3 = DynamicTaskScheduler.generateCronExpression(
    "1",                        // 单次执行
    executeTime,
    null,
    null
);
System.out.println(cron3);  // 输出: 0 0 18 30 6 ?

5.3 任务状态管理 ​

java
@Service
public class TaskStatusService {

    @Resource
    private DynamicTaskScheduler dynamicTaskScheduler;

    /**
     * 启用任务
     */
    public void enableTask(Long taskId) {
        AuditReportTaskConfigEntity taskConfig = getById(taskId);

        // 更新状态为启用
        taskConfig.setTaskStatus("1");
        updateById(taskConfig);

        // 启动任务
        startTask(taskConfig);
    }

    /**
     * 禁用任务
     */
    public void disableTask(Long taskId) {
        AuditReportTaskConfigEntity taskConfig = getById(taskId);

        // 更新状态为禁用
        taskConfig.setTaskStatus("0");
        updateById(taskConfig);

        // 停止任务
        closeTask(taskConfig);
    }

    /**
     * 暂停任务(保留配置,停止执行)
     */
    public void pauseTask(Long taskId) {
        AuditReportTaskConfigEntity taskConfig = getById(taskId);

        TimingTaskBaseDTO task = new TimingTaskBaseDTO();
        task.setTaskName("AUDIT_REPORT_TASK_" + taskConfig.getTaskName());

        dynamicTaskScheduler.removeTask(task);

        log.info("任务已暂停: {}", taskConfig.getTaskName());
    }

    /**
     * 恢复任务
     */
    public void resumeTask(Long taskId) {
        AuditReportTaskConfigEntity taskConfig = getById(taskId);
        startTask(taskConfig);
        log.info("任务已恢复: {}", taskConfig.getTaskName());
    }
}

六、Cron 表达式参考 ​

6.1 Cron 表达式格式 ​

秒 分 时 日 月 周 [年]

字段说明:

  • 秒: 0-59
  • 分: 0-59
  • 时: 0-23
  • 日: 1-31
  • 月: 1-12 或 JAN-DEC
  • 周: 1-7 或 SUN-SAT (1=星期一, 7=星期日)
  • 年: 可选,1970-2099

6.2 特殊字符 ​

  • *: 所有值
  • ?: 不指定值(日和周字段互斥使用)
  • -: 范围,如 10-12
  • ,: 列举,如 1,4,7,10
  • /: 步长,如 0/15 (每15分钟)
  • L: 最后,如 5L (本月最后一个星期五)
  • W: 工作日,如 15W (最接近15号的工作日)
  • #: 第几个,如 6#3 (本月第3个星期六)

6.3 常用 Cron 表达式示例 ​

0 0 0 * * ?        每天午夜执行
0 0 12 * * ?       每天中午12点执行
0 0 9-17 * * ?     每天9点到17点每小时执行
0 0/30 * * * ?     每30分钟执行
0 0 0 1 * ?        每月1号午夜执行
0 0 0 ? * 1        每周一午夜执行
0 0 0 1 1 ?        每年1月1日午夜执行
0 0 0 L * ?        每月最后一天午夜执行

七、注意事项 ​

7.1 任务名称唯一性 ​

  • 任务名称必须唯一,作为任务的唯一标识
  • 如果使用相同名称添加新任务,会自动取消旧任务
java
// 第一次调用
TimingTaskBaseDTO task1 = new TimingTaskBaseDTO("report_task", "1", executeDate, null, null);
dynamicTaskScheduler.scheduleTask(task1, runnable1);

// 第二次调用相同名称,会先取消task1,再启动新任务
TimingTaskBaseDTO task2 = new TimingTaskBaseDTO("report_task", "2", null, "1", "15");
dynamicTaskScheduler.scheduleTask(task2, runnable2);  // task1 被自动取消

7.2 线程安全 ​

  • DynamicTaskScheduler 使用 ConcurrentHashMap 存储任务,支持并发操作
  • 可以在多线程环境下安全地添加、删除任务

7.3 时区问题 ​

  • Cron 表达式使用服务器本地时区
  • 如果需要特定时区,需在应用配置中设置
yaml
# application.yml
spring:
  task:
    scheduling:
      pool:
        size: 10
  # 设置时区
  jackson:
    time-zone: Asia/Shanghai

7.4 任务执行异常处理 ​

  • 如果任务执行抛出异常,不会影响下次调度
  • 建议在 Runnable 实现中添加异常处理
java
@Override
public void run() {
    try {
        // 业务逻辑
        executeBusinessLogic();
    } catch (Exception e) {
        // 记录日志但不抛出异常
        log.error("定时任务执行失败", e);
        // 可选:发送告警通知
        sendAlertNotification(e);
    }
}

7.5 单次任务的特殊处理 ​

  • 单次任务执行完后不会自动移除,需要手动取消
  • 建议在业务逻辑中执行完后调用 removeTask
java
public class OneTimeTaskRunnable implements Runnable {

    private final DynamicTaskScheduler scheduler;
    private final TimingTaskBaseDTO taskConfig;

    @Override
    public void run() {
        try {
            // 执行业务逻辑
            executeBusinessLogic();
        } finally {
            // 执行完后自动移除任务
            scheduler.removeTask(taskConfig);
        }
    }
}

7.6 季度任务的月份计算 ​

  • 季度任务会自动计算对应的月份
  • 例如:periodVal="2,10" 表示每季度第二个月10号
    • 实际执行时间:2月10日、5月10日、8月10日、11月10日

7.7 性能优化建议 ​

  1. 合理设置线程池大小
yaml
spring:
  task:
    scheduling:
      pool:
        size: 20  # 根据任务数量调整
  1. 避免长时间运行的任务
java
// 不推荐
public void run() {
    // 执行耗时很长的操作
    processHugeDataSet();  // 可能运行几小时
}

// 推荐
public void run() {
    // 提交到异步线程池执行
    asyncExecutor.submit(() -> processHugeDataSet());
}
  1. 批量操作时避免频繁调用
java
// 不推荐
for (TaskConfig config : configs) {
    scheduler.scheduleTask(config, runnable);
}

// 推荐
configs.forEach(config -> {
    scheduler.scheduleTask(config, runnable);
});

八、故障排查 ​

8.1 任务未按预期执行 ​

检查步骤:

  1. 验证 Cron 表达式
java
String cron = DynamicTaskScheduler.generateCronExpression(...);
System.out.println("生成的Cron表达式: " + cron);

LocalDateTime nextTime = scheduler.getCronByData(cron);
System.out.println("下次执行时间: " + nextTime);
  1. 检查任务是否已注册
java
// 可以在DynamicTaskScheduler中添加调试方法
public Set<String> getAllTaskNames() {
    return taskMap.keySet();
}
  1. 查看日志
yaml
logging:
  level:
    org.springframework.scheduling: DEBUG
    com.pig4cloud.pigx.audit.infrastructure.scheduler: DEBUG

8.2 任务重复执行 ​

原因:

  • 任务名称重复
  • 应用重启时重复注册

解决方案:

java
@PostConstruct
public void init() {
    // 启动前先清理可能存在的任务
    TimingTaskBaseDTO task = new TimingTaskBaseDTO();
    task.setTaskName(taskName);
    scheduler.removeTask(task);

    // 再注册新任务
    scheduler.scheduleTask(task, runnable);
}

8.3 任务取消失败 ​

原因:

  • 任务名称不匹配
  • 任务已经执行完成

解决方案:

java
public void removeTask(TimingTaskBaseDTO task) {
    if (taskMap.containsKey(task.getTaskName())) {
        ScheduledFuture<?> future = taskMap.get(task.getTaskName());
        boolean cancelled = future.cancel(true);  // true表示中断正在执行的任务
        taskMap.remove(task.getTaskName());
        log.info("任务已取消: {}, 取消结果: {}", task.getTaskName(), cancelled);
    } else {
        log.warn("任务不存在: {}", task.getTaskName());
    }
}

九、完整配置示例 ​

9.1 Spring Boot 配置 ​

yaml
# application.yml
spring:
  task:
    scheduling:
      # 线程池配置
      pool:
        size: 20                      # 线程池大小
      thread-name-prefix: "task-"     # 线程名称前缀
      shutdown:
        await-termination: true       # 关闭时等待任务完成
        await-termination-period: 60  # 等待超时时间(秒)

# 日志配置
logging:
  level:
    com.pig4cloud.pigx.audit.infrastructure.scheduler: INFO
    org.springframework.scheduling: WARN

9.2 Bean 配置 ​

java
@Configuration
public class SchedulerConfig {

    /**
     * 配置线程池任务调度器
     */
    @Bean
    public ThreadPoolTaskScheduler taskScheduler() {
        ThreadPoolTaskScheduler scheduler = new ThreadPoolTaskScheduler();
        scheduler.setPoolSize(20);
        scheduler.setThreadNamePrefix("dynamic-task-");
        scheduler.setWaitForTasksToCompleteOnShutdown(true);
        scheduler.setAwaitTerminationSeconds(60);
        scheduler.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
        scheduler.initialize();
        return scheduler;
    }
}

十、接口参考 ​

10.1 DynamicTaskScheduler 主要方法 ​

java
/**
 * 添加/更新定时任务
 * @param task 任务配置
 * @param runnable 任务执行器
 * @return 下次执行时间
 */
public LocalDateTime scheduleTask(TimingTaskBaseDTO task, Runnable runnable)

/**
 * 取消任务
 * @param task 任务配置
 */
public void removeTask(TimingTaskBaseDTO task)

/**
 * 生成Cron表达式(静态方法)
 * @param executeType 执行类型
 * @param executeDate 执行时间
 * @param periodType 周期类型
 * @param periodVal 周期值
 * @return Cron表达式
 */
public static String generateCronExpression(
    String executeType,
    LocalDateTime executeDate,
    String periodType,
    String periodVal
)

/**
 * 根据Cron表达式计算下次执行时间
 * @param cronExpression Cron表达式
 * @return 下次执行时间
 */
public LocalDateTime getCronByData(String cronExpression)

十一、最佳实践总结 ​

  1. 任务命名规范

    • 使用统一的前缀:SERVICE_NAME_TASK_业务描述
    • 例如:AUDIT_REPORT_TASK_MONTHLY, DATA_SYNC_TASK_DAILY
  2. 任务执行器设计

    • 实现 Runnable 接口
    • 添加完善的异常处理
    • 记录详细的执行日志
    • 考虑幂等性设计
  3. 任务配置持久化

    • 将任务配置保存到数据库
    • 支持页面化管理
    • 应用启动时自动加载
  4. 监控和告警

    • 记录任务执行时长
    • 任务失败时发送告警
    • 统计任务执行成功率
  5. 优雅停机

    • 配置 await-termination: true
    • 设置合理的等待时间
    • 任务中定期检查中断标志

十二、版本历史 ​

v1.0.0 (2024-11) ​

  • ✅ 初始版本发布
  • ✅ 支持单次执行、定时执行
  • ✅ 支持按周、按月、按季度调度
  • ✅ 自动生成 Cron 表达式
  • ✅ 线程安全的任务管理

十三、技术支持 ​

如遇到问题,请按以下步骤处理:

  1. 查看本文档的"故障排查"章节
  2. 检查日志输出
  3. 验证 Cron 表达式是否正确
  4. 联系框架维护人员

维护团队: 审计系统开发组