介绍
@Scheduled
是 Spring 框架中的一个注解,用于实现定时任务。通过该注解,可以方便地配置方法在特定时间或间隔执行,适用于需要定期执行的任务,如数据清理、报表生成等。
-
用途:
@Scheduled
注解用于在 Spring 管理的 Bean 中声明方法为定时任务,从而实现周期性或按计划执行的后台任务。 -
启用方式:要使用
@Scheduled
注解,必须在配置类上添加@EnableScheduling
注解,以启用定时任务功能。
源代码
package org.springframework.scheduling.annotation;import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Repeatable;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.util.concurrent.TimeUnit;@Target({ElementType.METHOD, ElementType.ANNOTATION_TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Repeatable(Schedules.class)
public @interface Scheduled {String CRON_DISABLED = "-";String cron() default "";String zone() default "";long fixedDelay() default -1L;String fixedDelayString() default "";long fixedRate() default -1L;String fixedRateString() default "";long initialDelay() default -1L;String initialDelayString() default "";TimeUnit timeUnit() default TimeUnit.MILLISECONDS;
}
属性介绍
-
cron()
:接受一个 Cron 表达式,用于定义任务的执行时间表。默认值为空字符串,表示不使用 Cron 表达式。 -
zone()
:指定时区,用于 Cron 表达式的时间计算。默认值为空字符串,表示使用默认时区。 -
fixedDelay()
:指定任务执行完成后延迟固定时间再执行下一次,单位为毫秒。默认值为-1L
,表示不使用固定延迟。 -
fixedDelayString()
:与fixedDelay()
类似,但接受一个字符串值,允许使用表达式。 -
fixedRate()
:指定任务执行的固定时间间隔,单位为毫秒。默认值为-1L
,表示不使用固定速率。 -
fixedRateString()
:与fixedRate()
类似,但接受一个字符串值,允许使用表达式。 -
initialDelay()
:设置任务首次执行之前的延迟时间,单位为毫秒。默认值为-1L
,表示不使用初始延迟。 -
initialDelayString()
:与initialDelay()
类似,但接受一个字符串值,允许使用表达式。 -
timeUnit()
:指定时间单位,默认为TimeUnit.MILLISECONDS
。如果需要使用其他时间单位(如秒、分钟等),可以通过此属性指定。
注意事项
互斥性:
cron 和 fixedDelay/fixedRate 是互斥的,不能同时使用。
如果同时定义了 fixedDelay 和 fixedDelayString,或者 fixedRate 和 fixedRateString,则字符串版本优先。
单线程默认行为:
默认情况下,@Scheduled 使用单线程调度器。如果需要多线程执行,可以通过配置 ThreadPoolTaskExecutor 并设置 @EnableScheduling 的 executor 属性来实现。
异常处理:
如果任务抛出异常,Spring 默认会记录异常信息,但不会影响其他任务的执行。可以通过自定义异常处理逻辑来增强任务的健壮性。
示例代码
ScheduledDemoConfig
package com.yang.SpringTest.annotation.scheduledLearn;import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.EnableScheduling;/*** <p>Scheduled配置</p>** @author By: chengxuyuanshitang <br>* @Package: com.yang.SpringTest.annotation.scheduledLearn <br>* @CreateTime: 2025-02-06 09:28 <br>*/
@EnableScheduling
@Configuration
@ComponentScan(basePackages = "com.yang.SpringTest.annotation.scheduledLearn")
public class ScheduledDemoConfig {}
ScheduledDemoTasks
package com.yang.SpringTest.annotation.scheduledLearn;import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;import java.util.concurrent.TimeUnit;/*** <p>Tasks</p>** @author By: chengxuyuanshitang <br>* @Package: com.yang.SpringTest.annotation.scheduledLearn <br>* @CreateTime: 2025-02-06 09:30 <br>*/
@Component
public class ScheduledDemoTasks {/*** 每5秒执行一次*/@Scheduled(fixedRate = 5000)public void task1() {System.out.println("****************Task 1 executed at: " + System.currentTimeMillis());}/*** 每天中午12点执行*/@Scheduled(cron = "0 0 12 * * ?", zone = "GMT+8")public void task2() {System.out.println("****************Task 2 executed at: " + System.currentTimeMillis());}/*** 首次延迟10秒,之后每5秒执行一次*/@Scheduled(initialDelay = 10, fixedRate = 5, timeUnit = TimeUnit.SECONDS)public void task3() {System.out.println("**************** Task 3 executed at: " + System.currentTimeMillis());}
}
ScheduledDemoTest
package com.yang.SpringTest.annotation.scheduledLearn;import lombok.extern.slf4j.Slf4j;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;/*** <p>Scheduled注解测试</p>** @author By: chengxuyuanshitang <br>* @Package: com.yang.SpringTest.annotation.scheduledLearn <br>* @CreateTime: 2025-02-06 09:26 <br>*/
@Slf4j
public class ScheduledDemoTest {public static void main(String[] args) {AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(ScheduledDemoConfig.class);log.info("**************** IOC容器启动完成....");// 保持容器运行一段时间,观察定时任务的执行try {// 保持200秒Thread.sleep(200 * 1000);} catch (InterruptedException e) {Thread.currentThread().interrupt();}context.close();log.info("**************** IOC容器关闭....");}}