SpringBoot工程启动时自动执行任务实现方式

 更新时间:2025年09月04日 10:08:36   作者:angushine  
在SpringBoot中,推荐通过ApplicationRunner/CommandLineRunner或ApplicationReadyEvent监听实现启动时自动执行MQ任务,确保应用完全就绪,避免依赖未初始化问题,同时需配置连接池、重试机制及多环境控制,保障系统稳定与资源优雅关闭

在 Spring Boot 中实现工程启动时自动执行任务(如开始消费 MQ 数据)有多种可靠的方式。

以下是几种常用的方法:

1.使用CommandLineRunner或ApplicationRunner接口

2.使用@PostConstruct注解

3.使用ApplicationListener监听ApplicationReadyEvent事件

4.使用@EventListener注解监听应用上下文事件

其中,推荐使用ApplicationRunner或CommandLineRunner,或者监听ApplicationReadyEvent事件,因为此时应用上下文已经完全准备好,避免在应用还未完全初始化时就执行任务。

推荐实现方案

  1. 使用 ApplicationRunner或 CommandLineRunner(最常用)
import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import org.springframework.stereotype.Component;

@Component
public class MqConsumerStarter implements ApplicationRunner {

    private final MqConsumerService mqConsumerService;

    public MqConsumerStarter(MqConsumerService mqConsumerService) {
        this.mqConsumerService = mqConsumerService;
    }

    @Override
    public void run(ApplicationArguments args) throws Exception {
        // 应用启动后立即执行
        mqConsumerService.startConsuming();
    }
}

特点​​:

  • 在 ApplicationContext完全加载后执行
  • 可以访问所有 Spring Bean
  • 支持多个 Runner 并指定执行顺序
  1. 使用 @EventListener监听 ApplicationReadyEvent
import org.springframework.boot.context.event.ApplicationReadyEvent;
import org.springframework.context.event.EventListener;
import org.springframework.stereotype.Component;

@Component
public class MqConsumerInitializer {

    private final MqConsumerService mqConsumerService;

    public MqConsumerInitializer(MqConsumerService mqConsumerService) {
        this.mqConsumerService = mqConsumerService;
    }

    @EventListener(ApplicationReadyEvent.class)
    public void onApplicationReady() {
        // 应用完全启动后执行
        mqConsumerService.startConsuming();
    }
}

特点​​:

  • 在应用完全就绪后执行(包括所有 Runner 执行完毕)
  • 确保所有 Bean 已初始化完成
  • 避免在上下文未完全准备好时操作
  1. 使用 SmartLifecycle接口(适合长期运行任务)
import org.springframework.context.SmartLifecycle;
import org.springframework.stereotype.Component;

@Component
public class MqConsumerLifecycle implements SmartLifecycle {

    private final MqConsumerService mqConsumerService;
    private volatile boolean running = false;

    public MqConsumerLifecycle(MqConsumerService mqConsumerService) {
        this.mqConsumerService = mqConsumerService;
    }

    @Override
    public void start() {
        if (!running) {
            mqConsumerService.startConsuming();
            running = true;
        }
    }

    @Override
    public void stop() {
        if (running) {
            mqConsumerService.stopConsuming();
            running = false;
        }
    }

    @Override
    public boolean isRunning() {
        return running;
    }

    @Override
    public int getPhase() {
        return Integer.MAX_VALUE; // 最后启动
    }
}

特点​​:

  • 支持启动/停止生命周期管理
  • 可以控制启动顺序(通过 getPhase())
  • 适合需要优雅关闭的资源

MQ 消费实现示例(RabbitMQ)

  1. 配置 RabbitMQ 监听器
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.stereotype.Component;

@Component
public class RabbitMqConsumer {

    @RabbitListener(queues = "${mq.queue.name}")
    public void handleMessage(String message) {
        System.out.println("Received message: " + message);
        // 处理消息逻辑
    }
}
  1. 启动时自动创建队列和绑定
import org.springframework.amqp.core.Queue;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class RabbitMqConfig {

    @Bean
    public Queue myQueue() {
        return new Queue("${mq.queue.name}", true); // 持久化队列
    }
}
  1. 手动控制消费启停
import org.springframework.amqp.rabbit.listener.SimpleMessageListenerContainer;
import org.springframework.stereotype.Service;

@Service
public class MqConsumerService {

    private final SimpleMessageListenerContainer container;

    public MqConsumerService(SimpleMessageListenerContainer container) {
        this.container = container;
    }

    public void startConsuming() {
        if (!container.isRunning()) {
            container.start();
        }
    }

    public void stopConsuming() {
        if (container.isRunning()) {
            container.stop();
        }
    }
}

Kafka 消费实现示例

  1. 配置 Kafka 监听器
import org.springframework.kafka.annotation.KafkaListener;
import org.springframework.stereotype.Component;

@Component
public class KafkaConsumer {

    @KafkaListener(topics = "${kafka.topic.name}", groupId = "${kafka.group.id}")
    public void listen(String message) {
        System.out.println("Received Message: " + message);
        // 处理消息逻辑
    }
}
  1. 手动控制消费启停
import org.springframework.kafka.config.KafkaListenerEndpointRegistry;
import org.springframework.stereotype.Service;

@Service
public class KafkaConsumerService {

    private final KafkaListenerEndpointRegistry registry;

    public KafkaConsumerService(KafkaListenerEndpointRegistry registry) {
        this.registry = registry;
    }

    public void startConsuming() {
        registry.getListenerContainers().forEach(container -> {
            if (!container.isRunning()) {
                container.start();
            }
        });
    }

    public void stopConsuming() {
        registry.getListenerContainers().forEach(container -> {
            if (container.isRunning()) {
                container.stop();
            }
        });
    }
}

最佳实践与注意事项

  1. 启动顺序控制
// 使用 @Order 控制多个 Runner 的执行顺序
@Component
@Order(Ordered.HIGHEST_PRECEDENCE)
public class FirstRunner implements ApplicationRunner {
    // ...
}

@Component
@Order(Ordered.LOWEST_PRECEDENCE)
public class LastRunner implements ApplicationRunner {
    // ...
}
  1. 错误处理与重试机制
@Override
public void run(ApplicationArguments args) {
    try {
        mqConsumerService.startConsuming();
    } catch (Exception e) {
        // 添加重试逻辑
        int maxRetries = 5;
        for (int i = 0; i < maxRetries; i++) {
            try {
                Thread.sleep(5000); // 等待5秒重试
                mqConsumerService.startConsuming();
                break;
            } catch (Exception ex) {
                logger.error("Retry {} failed: {}", i+1, ex.getMessage());
            }
        }
    }
}
  1. 优雅关闭
import javax.annotation.PreDestroy;

@Component
public class MqConsumerLifecycle {

    @PreDestroy
    public void onShutdown() {
        // 应用关闭时停止消费
        mqConsumerService.stopConsuming();
    }
}

常见问题解决方案

  1. 依赖未初始化问题
// 使用 @DependsOn 确保依赖顺序
@Component
@DependsOn("mqConnectionFactory")
public class MqConsumerStarter implements ApplicationRunner {
    // ...
}
  1. 配置加载问题
@EventListener(ApplicationReadyEvent.class)
public void onApplicationReady() {
    // 确保所有配置已加载
}
  1. 多环境控制
@Profile("!test") // 不在测试环境启用
@Component
public class ProductionMqConsumer implements ApplicationRunner {
    // ...
}
  1. 并发启动问题
@Bean
public TaskExecutor taskExecutor() {
    ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
    executor.setCorePoolSize(1);
    executor.setMaxPoolSize(1);
    executor.setWaitForTasksToCompleteOnShutdown(true);
    return executor;
}

@Async("taskExecutor")
@Override
public void run(ApplicationArguments args) {
    // 单线程顺序执行
}

总结

在 Spring Boot 中实现启动时自动执行任务的最佳实践:

1.​​ 推荐使用​​:

  • ApplicationRunner或 CommandLineRunner:简单直接
  • @EventListener(ApplicationReadyEvent.class):确保完全就绪

2.​​ 复杂场景​​:

  • SmartLifecycle:需要生命周期管理
  • @PostConstruct+ @Async:异步执行

3.​​ 关键注意事项​​:

  • 确保依赖已初始化
  • 添加错误处理和重试机制
  • 实现优雅关闭
  • 集成健康检查
  • 多环境配置控制

4.​​ MQ 消费最佳实践​​:

  • 使用 Spring 原生支持(如 @RabbitListener)
  • 配置连接池和重试机制
  • 监控消费状态和性能

通过以上方法,可以可靠的在 Spring Boot 应用启动时自动执行 MQ 消费等初始化任务,确保系统稳定运行。

以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。

相关文章

  • Java中数组的使用与注意事项详解(推荐)

    Java中数组的使用与注意事项详解(推荐)

    数组是一组地址连续、长度固定的具有相同类型的数据的集合,通过数组下标我们可以指定数字中的每一个元素,下面这篇文章主要给大家介绍了关于Java中数组的使用与注意事项的相关资料,需要的朋友可以参考下
    2021-08-08
  • Java数据结构与算法之双向链表、环形链表及约瑟夫问题深入理解

    Java数据结构与算法之双向链表、环形链表及约瑟夫问题深入理解

    这篇文章主要介绍了Java数据结构与算法之双向链表、环形链表及约瑟夫问题深入理解,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2021-09-09
  • Spring Security权限注解启动及逻辑处理使用示例

    Spring Security权限注解启动及逻辑处理使用示例

    这篇文章主要为大家介绍了Spring Security权限注解启动及逻辑处理使用示例,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2023-07-07
  • SpringBoot+actuator和admin-UI实现监控中心方式

    SpringBoot+actuator和admin-UI实现监控中心方式

    这篇文章主要介绍了SpringBoot+actuator和admin-UI实现监控中心方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教
    2024-05-05
  • 详解JAVA的控制语句

    详解JAVA的控制语句

    这篇文章主要介绍了Java中的控制语句,循环等语句是Java编程中流程控制的基础,需要的朋友可以参考下,希望能够给你带来帮助
    2021-11-11
  • Java中输入与输出的方法总结

    Java中输入与输出的方法总结

    这篇文章主要为大家总结了一下Java中输入与输出的三种方法,文中通过示例详细的讲解了一下这些方法的使用,需要的小伙伴可以参考一下
    2022-04-04
  • Java版学生管理系统

    Java版学生管理系统

    这篇文章主要为大家详细介绍了Java版学生管理系统,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2022-06-06
  • SpringMVC框架如何与Junit整合看这个就够了

    SpringMVC框架如何与Junit整合看这个就够了

    这篇文章主要介绍了SpringMVC框架如何与Junit整合看这个就够了,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2021-05-05
  • Java读取DWG文件的完整步骤

    Java读取DWG文件的完整步骤

    DWG 是 AutoCAD 的专有二进制格式,直接解析难度大,通过开源库 Teigha File Converter(现更名 ODA File Converter)可实现格式转换,间接读取数据,本文给大家介绍了Java读取DWG文件的完整步骤,需要的朋友可以参考下
    2025-11-11
  • java反射获取和调用方法

    java反射获取和调用方法

    本篇内容主要给大家详细讲解了java反射获取方法以及调用方法,需要的朋友参考学习一下吧。
    2017-12-12

最新评论