Spring Boot 定时任务的多种实现方式
🌟 前言
欢迎来到我的技术小宇宙!🌌 这里不仅是我记录技术点滴的后花园,也是我分享学习心得和项目经验的乐园。📚 无论你是技术小白还是资深大牛,这里总有一些内容能触动你的好奇心。🔍
🤖 洛可可白:个人主页
🔥 个人专栏:✅前端技术 ✅后端技术
🏠 个人博客:洛可可白博客
🐱 代码获取:bestwishes0203
📷 封面壁纸:洛可可白wallpaper

这里写自定义目录标题
- Spring Boot 定时任务的多种实现方式
- 1. 使用 `@Scheduled` 注解
- 示例代码
- 优点
- 缺点
- 2. 使用 `ScheduledExecutorService`
- 示例代码
- 优点
- 缺点
- 3. 使用 Quartz 框架
- 示例代码
- 优点
- 缺点
- 4. 使用 `SchedulingConfigurer` 接口
- 示例代码
- 优点
- 缺点
- 5. 使用 `TaskScheduler` 接口
- 示例代码
- 优点
- 缺点
- 6. 使用 Redis 实现分布式定时任务
- 示例代码
- 优点
- 缺点
- 7. 使用 XXL-JOB 或 Elastic-Job
- 示例代码(XXL-JOB)
- 优点
- 缺点
- 总结
- 选择合适的定时任务实现方式
- 示例项目结构
- 示例代码完整版
- `DemoApplication.java`
- `SchedulingConfig.java`
- `ScheduledTask.java`
- `RedisConfig.java`
- `RedisDistributedTask.java`
- `application.properties`
- 结语
Spring Boot 定时任务的多种实现方式
在现代的 Spring Boot 应用程序中,定时任务是一种常见的需求。无论是定期清理日志、同步数据,还是执行定时的业务逻辑,Spring Boot 提供了多种灵活的方式来实现定时任务。本文将详细介绍几种常见的定时任务实现方式,并通过示例代码帮助你快速上手。
1. 使用 @Scheduled
注解
@Scheduled
是 Spring Boot 提供的一种简单且强大的定时任务实现方式,适用于大多数简单的定时任务场景。
示例代码
配置类:
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.EnableScheduling;
@Configuration
@EnableScheduling
public class SchedulingConfig {
// 启用定时任务支持
}
任务类:
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import java.time.LocalDateTime;
@Component
public class ScheduledTask {
// 固定频率:每5秒执行一次任务
@Scheduled(fixedRate = 5000)
public void executeTask() {
System.out.println("【@Scheduled 任务】执行时间:" + LocalDateTime.now());
}
// Cron 表达式:每天中午12点执行一次任务
@Scheduled(cron = "0 0 12 * * ?")
public void executeCronTask() {
System.out.println("【Cron 任务】执行时间:" + LocalDateTime.now());
}
}
优点
- 简单易用:只需添加注解即可实现定时任务。
- 集成度高:与 Spring 容器无缝集成,支持依赖注入。
缺点
- 单节点运行:默认情况下,
@Scheduled
任务仅在单个节点上运行,不支持分布式场景。
2. 使用 ScheduledExecutorService
ScheduledExecutorService
是 Java 提供的原生定时任务工具,适合需要更细粒度控制的任务调度场景。
示例代码
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
public class ScheduledExecutorServiceExample {
public static void main(String[] args) {
ScheduledExecutorService executor = Executors.newScheduledThreadPool(1);
executor.scheduleAtFixedRate(() -> {
System.out.println("任务执行:" + System.currentTimeMillis());
}, 0, 5, TimeUnit.SECONDS);
}
}
优点
- 灵活性高:可以自定义线程池大小和任务执行策略。
- 独立性强:不依赖于 Spring 框架,适合非 Spring 环境。
缺点
- 功能有限:不支持复杂的时间调度策略,如 Cron 表达式。
3. 使用 Quartz 框架
Quartz 是一个功能强大的任务调度框架,支持复杂的调度任务,例如动态任务配置和分布式任务调度。
示例代码
依赖:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-quartz</artifactId>
</dependency>
任务类:
import org.quartz.Job;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
public class MyJob implements Job {
@Override
public void execute(JobExecutionContext context) throws JobExecutionException {
System.out.println("Quartz 任务执行:" + System.currentTimeMillis());
}
}
配置类:
import org.quartz.*;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class QuartzConfig {
@Bean
public JobDetail jobDetail() {
return JobBuilder.newJob(MyJob.class)
.withIdentity("myJob")
.storeDurably()
.build();
}
@Bean
public Trigger jobTrigger(JobDetail jobDetail) {
return TriggerBuilder.newTrigger()
.forJob(jobDetail)
.withIdentity("myTrigger")
.withSchedule(SimpleScheduleBuilder.simpleSchedule()
.withIntervalInSeconds(5)
.repeatForever())
.build();
}
}
优点
- 功能强大:支持复杂的调度策略,如动态任务配置和分布式任务调度。
- 高可靠性:支持任务持久化和恢复。
缺点
- 配置复杂:需要额外的配置和依赖。
- 学习曲线:相比
@Scheduled
,Quartz 的学习成本较高。
4. 使用 SchedulingConfigurer
接口
SchedulingConfigurer
是 Spring 提供的一个接口,允许动态配置定时任务,例如从数据库中读取任务配置。
示例代码
import org.springframework.scheduling.config.ScheduledTaskRegistrar;
import org.springframework.scheduling.annotation.SchedulingConfigurer;
import org.springframework.scheduling.Trigger;
import org.springframework.scheduling.TriggerContext;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.scheduling.support.CronTrigger;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import java.util.Date;
@Configuration
public class DynamicSchedulingConfig implements SchedulingConfigurer {
@Override
public void configureTasks(ScheduledTaskRegistrar taskRegistrar) {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setCorePoolSize(10);
executor.initialize();
taskRegistrar.setTaskExecutor(executor);
taskRegistrar.addTriggerTask(
() -> System.out.println("动态任务执行:" + new Date()),
new Trigger() {
@Override
public Date nextExecutionTime(TriggerContext triggerContext) {
return new CronTrigger("0/5 * * * * ?").nextExecutionTime(triggerContext);
}
}
);
}
}
优点
- 动态配置:支持从外部动态加载任务配置。
- 灵活性高:可以结合数据库或其他存储实现动态任务管理。
缺点
- 复杂度高:实现动态任务配置需要额外的开发工作。
5. 使用 TaskScheduler
接口
TaskScheduler
是 Spring 提供的一个接口,支持动态任务调度,适合需要动态调整任务执行频率的场景。
示例代码
import org.springframework.scheduling.TaskScheduler;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.scheduling.annotation.SchedulingConfigurer;
import org.springframework.scheduling.config.ScheduledTaskRegistrar;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import java.util.Date;
@Configuration
@EnableScheduling
public class TaskSchedulerConfig implements SchedulingConfigurer {
@Override
public void configureTasks(ScheduledTaskRegistrar taskRegistrar) {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setCorePoolSize(10);
executor.initialize();
taskRegistrar.setTaskExecutor(executor);
taskRegistrar.addFixedRateTask(() -> System.out.println("固定频率任务执行:" + new Date()), 5000);
}
}
优点
- 动态调度:支持动态调整任务执行频率。
- 简单易用:与 Spring 容器无缝集成。
缺点
- 功能有限:不支持复杂的时间调度策略。
6. 使用 Redis 实现分布式定时任务
Redis 是一个高性能的键值存储系统,可以利用其特性实现简单的分布式定时任务。
示例代码
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
@Component
public class RedisDistributedTask {
private final RedisTemplate<String, String> redisTemplate;
public RedisDistributedTask(RedisTemplate<String, String> redisTemplate) {
this.redisTemplate = redisTemplate;
}
@Scheduled(fixedRate = 5000)
public void executeTask() {
String lockKey = "distributedTaskLock";
String lockValue = String.valueOf(System.currentTimeMillis());
Boolean lock = redisTemplate.opsForValue().setIfAbsent(lockKey, lockValue, 5, TimeUnit.SECONDS);
if (lock != null && lock) {
System.out.println("分布式任务执行:" + new Date());
}
}
}
优点
- 分布式支持:可以实现简单的分布式任务调度。
- 简单易用:基于 Redis 的特性,实现简单。
缺点
- 功能有限:不支持复杂的调度策略。
7. 使用 XXL-JOB 或 Elastic-Job
XXL-JOB 和 Elastic-Job 是轻量级的分布式任务调度平台,支持动态任务管理和高可用性。
示例代码(XXL-JOB)
依赖:
<dependency>
<groupId>com.xuxueli</groupId>
<artifactId>xxl-job-core</artifactId>
<version>3.1.2</version>
</dependency>
任务类:
import com.xxl.job.core.handler.annotation.XxlJob;
import org.springframework.stereotype.Component;
@Component
public class XxlJobExample {
@XxlJob("myJobHandler")
public void myJobHandler() {
System.out.println("XXL-JOB 任务执行:" + System.currentTimeMillis());
}
}
配置类(XXL-JOB)
import com.xxl.job.core.executor.impl.XxlJobSpringExecutor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class XxlJobConfig {
@Bean
public XxlJobSpringExecutor xxlJobExecutor() {
XxlJobSpringExecutor xxlJobSpringExecutor = new XxlJobSpringExecutor();
xxlJobSpringExecutor.setAdminAddresses("http://127.0.0.1:8080/xxl-job-admin");
xxlJobSpringExecutor.setAppname("xxl-job-executor-sample");
xxlJobSpringExecutor.setIp("127.0.0.1");
xxlJobSpringExecutor.setPort(9999);
return xxlJobSpringExecutor;
}
}
优点
- 功能强大:支持动态任务管理、分布式任务调度、任务监控等功能。
- 高可用性:支持任务的容错和恢复机制。
- 易于集成:与 Spring Boot 集成简单,配置方便。
缺点
- 学习成本:需要额外学习 XXL-JOB 或 Elastic-Job 的使用方式。
- 依赖外部系统:需要部署额外的调度中心(如 XXL-JOB 的管理平台)。
总结
在 Spring Boot 中,有多种方式可以实现定时任务,每种方式都有其适用场景和优缺点:
实现方式 | 优点 | 缺点 | 适用场景 |
---|---|---|---|
@Scheduled 注解 | 简单易用,与 Spring 集成度高 | 不支持分布式任务 | 单节点应用,简单任务调度 |
ScheduledExecutorService | 灵活性高,适合复杂任务调度 | 不支持复杂的时间调度策略 | 需要自定义线程池的任务调度 |
Quartz 框架 | 功能强大,支持复杂调度策略和分布式任务 | 配置复杂,学习成本高 | 需要复杂调度策略的应用 |
SchedulingConfigurer 接口 | 支持动态任务配置 | 实现复杂,需要额外开发工作 | 动态任务配置需求 |
TaskScheduler 接口 | 动态调度,与 Spring 集成度高 | 功能有限,不支持复杂调度策略 | 动态调整任务执行频率的场景 |
Redis 分布式任务 | 支持分布式任务调度,实现简单 | 功能有限,不支持复杂调度策略 | 分布式任务调度,简单场景 |
XXL-JOB / Elastic-Job | 功能强大,支持动态任务管理和高可用性 | 需要额外部署调度中心,学习成本高 | 分布式任务调度,复杂场景 |
选择合适的定时任务实现方式
选择哪种定时任务实现方式取决于你的具体需求:
- 简单任务调度:如果任务逻辑简单,且仅在单个节点上运行,推荐使用
@Scheduled
注解。 - 复杂任务调度:如果需要支持复杂的时间调度策略(如 Cron 表达式),或者需要分布式任务调度,可以考虑使用 Quartz 框架。
- 动态任务配置:如果任务配置需要动态加载(如从数据库中读取),可以使用
SchedulingConfigurer
接口。 - 分布式任务调度:如果需要在多个节点上运行任务,且任务调度需要高可用性,推荐使用 XXL-JOB 或 Elastic-Job。
- 轻量级任务调度:如果需要快速实现简单的分布式任务调度,可以考虑使用 Redis。
示例项目结构
以下是一个简单的 Spring Boot 项目结构,展示了如何集成 @Scheduled
和 Redis 分布式任务:
my-spring-boot-project/
├── src/
│ ├── main/
│ │ ├── java/
│ │ │ ├── com.example.demo/
│ │ │ │ ├── application/
│ │ │ │ │ ├── DemoApplication.java
│ │ │ │ ├── config/
│ │ │ │ │ ├── SchedulingConfig.java
│ │ │ │ │ ├── RedisConfig.java
│ │ │ │ ├── service/
│ │ │ │ │ ├── ScheduledTask.java
│ │ │ │ │ ├── RedisDistributedTask.java
│ │ │ │ ├── model/
│ │ │ │ ├── controller/
│ │ │ │ ├── repository/
│ │ │ │ ├── util/
│ │ │ ├── resources/
│ │ │ │ ├── application.properties
│ │ │ │ ├── static/
│ │ │ │ ├── templates/
│ │ ├── test/
│ │ │ ├── java/
│ │ │ │ ├── com.example.demo/
│ │ │ │ │ ├── DemoApplicationTests.java
│ │ │ ├── resources/
│ ├── pom.xml
示例代码完整版
DemoApplication.java
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class DemoApplication {
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
}
SchedulingConfig.java
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.EnableScheduling;
@Configuration
@EnableScheduling
public class SchedulingConfig {
// 启用定时任务支持
}
ScheduledTask.java
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import java.time.LocalDateTime;
@Component
public class ScheduledTask {
// 固定频率:每5秒执行一次任务
@Scheduled(fixedRate = 5000)
public void executeTask() {
System.out.println("【@Scheduled 任务】执行时间:" + LocalDateTime.now());
}
// Cron 表达式:每天中午12点执行一次任务
@Scheduled(cron = "0 0 12 * * ?")
public void executeCronTask() {
System.out.println("【Cron 任务】执行时间:" + LocalDateTime.now());
}
}
RedisConfig.java
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;
@Configuration
public class RedisConfig {
@Bean
public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) {
RedisTemplate<String, Object> template = new RedisTemplate<>();
template.setConnectionFactory(redisConnectionFactory);
// 设置 Key 的序列化器
template.setKeySerializer(new StringRedisSerializer());
template.setHashKeySerializer(new StringRedisSerializer());
// 设置 Value 的序列化器
template.setValueSerializer(new GenericJackson2JsonRedisSerializer());
template.setHashValueSerializer(new GenericJackson2JsonRedisSerializer());
template.afterPropertiesSet();
return template;
}
}
RedisDistributedTask.java
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import java.util.Date;
@Component
public class RedisDistributedTask {
private final RedisTemplate<String, String> redisTemplate;
@Autowired
public RedisDistributedTask(RedisTemplate<String, String> redisTemplate) {
this.redisTemplate = redisTemplate;
}
@Scheduled(fixedRate = 5000)
public void executeTask() {
String lockKey = "distributedTaskLock";
String lockValue = String.valueOf(System.currentTimeMillis());
Boolean lock = redisTemplate.opsForValue().setIfAbsent(lockKey, lockValue, 5, TimeUnit.SECONDS);
if (lock != null && lock) {
System.out.println("分布式任务执行:" + new Date());
}
}
}
application.properties
# Redis 配置
spring.data.redis.host=localhost
spring.data.redis.port=6379
spring.data.redis.password=
结语
通过本文的介绍,你应该对 Spring Boot 中的定时任务实现方式有了更全面的了解。无论是简单的单节点任务,还是复杂的分布式任务,Spring Boot 都提供了灵活的解决方案。希望这些示例代码能帮助你快速实现定时任务的需求。
如果你有任何问题或建议,欢迎在评论区留言。
如果对你有帮助,点赞👍、收藏💖、关注🔔是我更新的动力!👋🌟🚀