Spring定时任务修仙指南:从@Scheduled到分布式调度的终极奥义

各位被Thread.sleep()while(true)折磨的Spring道友们!今天要解锁的是Spring生态自带的定时任务三件套 ------@ScheduledTaskScheduler@Async定时组合技!无需引入外部依赖,轻松实现从简单定时到分布式调度的全场景覆盖!准备好抛弃Quartz的复杂配置了吗? ⏰


一、筑基篇:@Scheduled基础用法

1.1 开启定时任务(激活灵脉)
java 复制代码
@SpringBootApplication
@EnableScheduling // 关键注解!放在启动类上
public class MyApp {
    public static void main(String[] args) {
        SpringApplication.run(MyApp.class, args);
    }
}
1.2 定时方法配置(三套仙术)
java 复制代码
@Component
public class MyTask {

    // 1. 固定速率(上次开始后间隔固定时间)
    @Scheduled(fixedRate = 5000) // 每5秒执行
    public void task1() {
        System.out.println("固定速率任务:" + LocalDateTime.now());
    }

    // 2. 固定延迟(上次结束后间隔固定时间)
    @Scheduled(fixedDelay = 3000) // 每次执行完等3秒
    public void task2() throws InterruptedException {
        Thread.sleep(1000); // 模拟耗时
        System.out.println("固定延迟任务:" + LocalDateTime.now());
    }

    // 3. Cron表达式(天庭历法)
    @Scheduled(cron = "0 0/5 9-18 * * MON-FRI") // 工作日9-18点每5分钟
    public void task3() {
        System.out.println("Cron任务:" + LocalDateTime.now());
    }
}

二、金丹篇:高级配置技巧

2.1 动态修改定时规则(天机可变)
java 复制代码
@RestController
public class TaskController {

    @Autowired
    private ScheduledTaskRegistrar taskRegistrar;

    @PostMapping("/update-task")
    public String updateTask(@RequestParam String newCron) {
        // 取消原有任务
        taskRegistrar.destroy();
        
        // 添加新任务
        taskRegistrar.addCronTask(
            () -> System.out.println("动态任务执行: " + LocalDateTime.now()),
            newCron
        );
        
        taskRegistrar.afterPropertiesSet();
        return "任务已更新为: " + newCron;
    }
}
2.2 异步定时任务(分身术)
java 复制代码
@Configuration
@EnableAsync // 开启异步支持
public class AsyncConfig implements AsyncConfigurer {
    @Override
    public Executor getAsyncExecutor() {
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        executor.setCorePoolSize(5);
        executor.setMaxPoolSize(10);
        executor.setQueueCapacity(100);
        executor.initialize();
        return executor;
    }
}

@Component
public class AsyncTask {
    @Async
    @Scheduled(fixedRate = 3000)
    public void asyncTask() {
        System.out.println("异步任务线程:" + Thread.currentThread().getName());
    }
}

三、元婴篇:分布式定时任务

3.1 基于Redis的分布式锁(防重复执行)
java 复制代码
@Component
public class DistributedTask {

    @Autowired
    private RedissonClient redisson;

    @Scheduled(cron = "0 0/5 * * * ?")
    public void distributedJob() {
        RLock lock = redisson.getLock("scheduled:lock");
        try {
            if (lock.tryLock(0, 30, TimeUnit.SECONDS)) {
                System.out.println("获取锁成功,执行任务...");
                // 业务代码...
            }
        } finally {
            if (lock.isHeldByCurrentThread()) {
                lock.unlock();
            }
        }
    }
}
3.2 结合ShedLock实现(推荐)
xml 复制代码
<!-- 添加依赖 -->
<dependency>
    <groupId>net.javacrumbs.shedlock</groupId>
    <artifactId>shedlock-spring</artifactId>
    <version>4.42.0</version>
</dependency>
<dependency>
    <groupId>net.javacrumbs.shedlock</groupId>
    <artifactId>shedlock-provider-jdbc-template</artifactId>
    <version>4.42.0</version>
</dependency>
java 复制代码
@Configuration
@EnableSchedulerLock(defaultLockAtMostFor = "10m")
public class ShedLockConfig {
    @Bean
    public LockProvider lockProvider(DataSource dataSource) {
        return new JdbcTemplateLockProvider(dataSource);
    }
}

@Service
public class ShedLockTask {
    @Scheduled(cron = "0 0/5 * * * ?")
    @SchedulerLock(name = "reportTask", lockAtLeastFor = "5m")
    public void scheduledTask() {
        // 保证同一时间只有一个实例执行
    }
}

四、化神篇:监控与管理

4.1 暴露执行端点(Spring Boot Actuator)
yaml 复制代码
# application.yml
management:
  endpoints:
    web:
      exposure:
        include: scheduledtasks
  endpoint:
    scheduledtasks:
      enabled: true

访问/actuator/scheduledtasks查看所有定时任务:

json 复制代码
{
  "cron": [
    {
      "runnable": {
        "target": "com.example.MyTask.task3"
      },
      "expression": "0 0/5 9-18 * * MON-FRI"
    }
  ],
  "fixedDelay": [],
  "fixedRate": []
}
4.2 自定义任务监控(天眼通)
java 复制代码
@Bean
public ScheduledTaskPostProcessor taskPostProcessor() {
    return new ScheduledTaskPostProcessor() {
        @Override
        public void postProcessAfterInitialization(Object bean, String beanName) {
            // 监控所有定时任务初始化
            System.out.println("已加载定时任务: " + beanName);
        }
    };
}

五、大乘篇:最佳实践

5.1 任务执行日志记录
java 复制代码
@Aspect
@Component
public class TaskLogAspect {

    @Around("@annotation(scheduled)")
    public Object logTask(ProceedingJoinPoint pjp, Scheduled scheduled) throws Throwable {
        String taskName = pjp.getSignature().toShortString();
        long start = System.currentTimeMillis();
        try {
            System.out.println("任务开始: " + taskName);
            return pjp.proceed();
        } finally {
            System.out.printf("任务结束: %s, 耗时: %dms%n", 
                taskName, System.currentTimeMillis() - start);
        }
    }
}
5.2 异常处理策略
java 复制代码
@Scheduled(fixedRate = 5000)
public void errorProneTask() {
    try {
        // 业务代码...
    } catch (Exception e) {
        // 1. 记录异常到数据库
        // 2. 发送报警邮件
        // 3. 根据策略决定是否重试
        System.err.println("任务执行失败: " + e.getMessage());
    }
}

渡劫指南:常见问题

问题 解决方案
任务不执行 检查@EnableScheduling是否启用
Cron表达式无效 使用在线工具校验表达式
多任务串行执行 配置TaskScheduler线程池
分布式环境重复执行 集成ShedLock或Redis分布式锁
时区问题 设置spring.task.scheduling.pool.size

相关推荐
怡人蝶梦30 分钟前
Java后端技术栈问题排查实战:Spring Boot启动慢、Redis缓存击穿与Kafka消费堆积
java·jvm·redis·kafka·springboot·prometheus
瓯雅爱分享34 分钟前
MES管理系统:Java+Vue,含源码与文档,实现生产过程实时监控、调度与优化,提升制造企业效能
java·mysql·vue·软件工程·源代码管理
蓝色天空的银码星35 分钟前
Springcloud Alibaba自定义负载均衡详解
spring·spring cloud·负载均衡
鬼多不菜1 小时前
一篇学习CSS的笔记
java·前端·css
深色風信子1 小时前
Eclipse 插件开发 5.3 编辑器 监听输入
java·eclipse·编辑器·编辑器 监听输入·插件 监听输入
yezipi耶不耶1 小时前
Rust入门之并发编程基础(一)
开发语言·后端·rust
bobz9652 小时前
cirros 慢的原因 checking http://169.254.169.254
后端
Blossom.1182 小时前
人工智能在智能健康监测中的创新应用与未来趋势
java·人工智能·深度学习·机器学习·语音识别
shangjg32 小时前
Kafka 如何保证不重复消费
java·分布式·后端·kafka