说说spring 注解@Scheduled的实现原理以及用法?

1 个回答

  • 灵儿
    入体冰凉的月光,都比不上你绝情的目光。
    ## **1. `@Scheduled` 的作用** Spring 的 `@Scheduled` 注解用于**在 Spring 应用中配置和执行定时任务**,它可以: - **基于固定时间间隔** (`fixedRate`) - **基于固定延迟时间** (`fixedDelay`) - **基于 Cron 表达式** (`cron`) ## **2. `@Scheduled` 的底层实现原理** ### **(1)核心组件** Spring 内部有几个关键组件实现 `@Scheduled` 的定时任务调度: #### **1️⃣ `ScheduledAnnotationBeanPostProcessor`(核心处理器)** - **作用**:Spring **自动扫描** `@Scheduled` 注解的方法,并注册为调度任务。 - **执行流程**: 1. 在 `postProcessAfterInitialization` 阶段,扫描 `@Scheduled` 方法。 2. 提取 `@Scheduled` 的调度信息(如 `fixedRate`、`cron`)。 3. 将任务注册到 `ScheduledTaskRegistrar` 进行管理。 ```java @Override public void postProcessAfterInitialization(Object bean, String beanName) throws BeansException { Class<?> targetClass = AopProxyUtils.ultimateTargetClass(bean); ReflectionUtils.doWithMethods(targetClass, this::processScheduled, ReflectionUtils.USER_DECLARED_METHODS); } ``` #### **2️⃣ `ScheduledTaskRegistrar`(任务注册器)** - `ScheduledAnnotationBeanPostProcessor` **最终会调用 `ScheduledTaskRegistrar` 来管理定时任务**。 - `ScheduledTaskRegistrar` 维护任务列表,并将任务交给 `TaskScheduler` 处理。 - **任务调度核心代码:** ```java tasks.add(this.registrar.scheduleFixedRateTask(new FixedRateTask(runnable, fixedRate, delayToUse))); ``` #### **3️⃣ `TaskScheduler`(任务调度器)** Spring 提供 `TaskScheduler` 进行任务调度: - 默认使用 **`ConcurrentTaskScheduler`**,底层基于 **`ScheduledExecutorService`** 线程池实现。 - 也可以自定义线程池,提高任务并发执行能力。 ```java public class ConcurrentTaskScheduler extends ConcurrentTaskExecutor implements TaskScheduler { private final ScheduledExecutorService scheduledExecutor = Executors.newSingleThreadScheduledExecutor(); } ``` ### **(2)任务调度的执行流程** 1. **Spring 容器启动时,`ScheduledAnnotationBeanPostProcessor` 扫描 `@Scheduled` 方法。** 2. **将定时任务注册到 `ScheduledTaskRegistrar`,并交给 `TaskScheduler` 调度。** 3. **默认使用 `ConcurrentTaskScheduler`(基于 `ScheduledExecutorService` 线程池)执行任务。** 4. **任务按照 `fixedRate`、`fixedDelay` 或 `cron` 规则调度执行。** ## **3. `@Scheduled` 的用法** ### **(1)启用定时任务** 必须添加 `@EnableScheduling` 注解,否则 `@Scheduled` 不会生效: ```java @Configuration @EnableScheduling public class SchedulerConfig { } ``` ### **(2)定义定时任务** ```java import org.springframework.scheduling.annotation.Scheduled; import org.springframework.stereotype.Component; @Component public class ScheduledTasks { // 每 5 秒执行一次(从任务开始时间算起) @Scheduled(fixedRate = 5000) public void fixedRateTask() { System.out.println("FixedRate Task 执行:" + System.currentTimeMillis()); } // 上一个任务完成后等待 5 秒再执行 @Scheduled(fixedDelay = 5000) public void fixedDelayTask() { System.out.println("FixedDelay Task 执行:" + System.currentTimeMillis()); } // 每天晚上 12 点执行(基于 Cron 表达式) @Scheduled(cron = "0 0 0 * * ?") public void cronTask() { System.out.println("Cron Task 执行:" + System.currentTimeMillis()); } } ``` ### **(3)@Scheduled 参数说明** | 参数 | 作用 | 示例 | |------|------|------| | `fixedRate` | **从上一次任务开始时间**计算固定间隔执行 | `@Scheduled(fixedRate = 5000)` | | `fixedDelay` | **从上一次任务完成时间**计算固定间隔执行 | `@Scheduled(fixedDelay = 5000)` | | `cron` | 使用 **Cron 表达式**定义执行时间 | `@Scheduled(cron = "0 0 0 * * ?")` | ## **4. 自定义线程池(提高并发能力)** 默认 `@Scheduled` **使用单线程**,可能导致任务阻塞。可以配置 **自定义线程池** 提高并发。 ### **(1)定义线程池** ```java @Configuration public class SchedulerThreadPoolConfig { @Bean public ThreadPoolTaskScheduler taskScheduler() { ThreadPoolTaskScheduler scheduler = new ThreadPoolTaskScheduler(); scheduler.setPoolSize(5); // 线程池大小 scheduler.setThreadNamePrefix("MyScheduler-"); scheduler.initialize(); return scheduler; } } ``` ### **(2)指定线程池** ```java @Configuration @EnableScheduling public class SchedulerConfig implements SchedulingConfigurer { @Autowired private ThreadPoolTaskScheduler taskScheduler; @Override public void configureTasks(ScheduledTaskRegistrar taskRegistrar) { taskRegistrar.setTaskScheduler(taskScheduler); } } ``` ✅ 这样,Spring 的定时任务就会使用 **自定义线程池**,避免单线程阻塞问题。 ## **5. `@Scheduled` 底层原理总结** | 组件 | 作用 | |------|------| | `@Scheduled` | 标注定时任务方法,定义调度规则 | | `ScheduledAnnotationBeanPostProcessor` | 解析 `@Scheduled` 并注册任务 | | `ScheduledTaskRegistrar` | 任务管理器,负责存储任务信息 | | `TaskScheduler` | 任务调度器,基于 `ScheduledExecutorService` 线程池执行任务 | | `ConcurrentTaskScheduler` | 默认调度器,底层使用 `ScheduledExecutorService` | ## **6. 结论** 1. **`@Scheduled` 是 Spring 内置的定时任务方案,基于 `ScheduledExecutorService` 实现。** 2. **Spring 通过 `ScheduledAnnotationBeanPostProcessor` 解析 `@Scheduled` 并注册任务。** 3. **任务交由 `ScheduledTaskRegistrar` 统一管理,并通过 `TaskScheduler` 调度执行。** 4. **默认 `@Scheduled` 使用单线程,可通过 `ThreadPoolTaskScheduler` 自定义线程池,提高并发能力。** 5. **支持 `fixedRate`、`fixedDelay` 和 `cron` 三种调度方式,适用于不同场景的定时任务需求。**
    编辑于 2025-03-10 17:39 •IP属地 美国
    举报
    评论
    收藏