SpringBoot启动时自动执行特定代码的完整指南

 更新时间:2025年04月27日 09:19:16   作者:北辰alk  
Spring Boot 提供了多种灵活的方式在应用启动时执行初始化代码,以下是所有可行方法的详细说明和最佳实践,大家可以根据自己的需求进行选择

一、应用生命周期回调方式

1. CommandLineRunner 接口

@Component
@Order(1) // 可选,定义执行顺序
public class DatabaseInitializer implements CommandLineRunner {
    
    private final UserRepository userRepository;
    
    public DatabaseInitializer(UserRepository userRepository) {
        this.userRepository = userRepository;
    }
    
    @Override
    public void run(String... args) throws Exception {
        // 初始化数据库数据
        userRepository.save(new User("admin", "admin@example.com"));
        System.out.println("数据库初始化完成");
    }
}

特点:

  • 在所有ApplicationReadyEvent之前执行
  • 可以访问命令行参数
  • 支持多实例,通过@Order控制顺序

2. ApplicationRunner 接口

@Component
@Order(2)
public class CacheWarmup implements ApplicationRunner {
    
    @Override
    public void run(ApplicationArguments args) throws Exception {
        // 更丰富的参数访问方式
        System.out.println("源参数: " + args.getSourceArgs());
        System.out.println("选项参数: " + args.getOptionNames());
        
        // 预热缓存逻辑
        System.out.println("缓存预热完成");
    }
}

与CommandLineRunner区别:

  • 提供更结构化的参数访问(ApplicationArguments)
  • 同样支持@Order排序

二、Spring事件监听方式

1. 监听特定生命周期事件

@Component
public class StartupEventListener {
    
    // 在环境准备完成后执行
    @EventListener(ApplicationEnvironmentPreparedEvent.class)
    public void handleEnvPrepared(ApplicationEnvironmentPreparedEvent event) {
        ConfigurableEnvironment env = event.getEnvironment();
        System.out.println("当前环境: " + env.getActiveProfiles());
    }
    
    // 在应用上下文准备好后执行
    @EventListener(ApplicationContextInitializedEvent.class)
    public void handleContextInit(ApplicationContextInitializedEvent event) {
        System.out.println("应用上下文初始化完成");
    }
    
    // 在所有Bean加载完成后执行
    @EventListener(ContextRefreshedEvent.class)
    public void handleContextRefresh(ContextRefreshedEvent event) {
        System.out.println("所有Bean已加载");
    }
    
    // 在应用完全启动后执行(推荐)
    @EventListener(ApplicationReadyEvent.class)
    public void handleAppReady(ApplicationReadyEvent event) {
        System.out.println("应用已完全启动,可以开始处理请求");
    }
}

2. 事件执行顺序

三、Bean生命周期回调

1. @PostConstruct 注解

@Service
public class SystemValidator {
    
    @Autowired
    private HealthCheckService healthCheckService;
    
    @PostConstruct
    public void validateSystem() {
        if (!healthCheckService.isDatabaseConnected()) {
            throw new IllegalStateException("数据库连接失败");
        }
        System.out.println("系统验证通过");
    }
}

特点:

  • 在Bean依赖注入完成后立即执行
  • 适用于单个Bean的初始化
  • 抛出异常会阻止应用启动

2. InitializingBean 接口

@Component
public class NetworkChecker implements InitializingBean {
    
    @Override
    public void afterPropertiesSet() throws Exception {
        System.out.println("网络连接检查完成");
        // 执行网络检查逻辑
    }
}

与@PostConstruct比较:

  • 功能类似,但属于Spring接口而非JSR-250标准
  • 执行时机稍晚于@PostConstruct

四、Spring Boot特性扩展

1. ApplicationContextInitializer

public class CustomInitializer implements ApplicationContextInitializer<ConfigurableApplicationContext> {
    
    @Override
    public void initialize(ConfigurableApplicationContext applicationContext) {
        // 在上下文刷新前执行
        System.out.println("应用上下文初始化器执行");
        // 可以修改环境配置
        applicationContext.getEnvironment().setActiveProfiles("dev");
    }
}

注册方式:

1.在META-INF/spring.factories中添加:

org.springframework.context.ApplicationContextInitializer=com.example.CustomInitializer

2.或通过SpringApplication添加:

@SpringBootApplication
public class MyApp {
    public static void main(String[] args) {
        SpringApplication app = new SpringApplication(MyApp.class);
        app.addInitializers(new CustomInitializer());
        app.run(args);
    }
}

2. SpringApplicationRunListener

public class StartupMonitor implements SpringApplicationRunListener {
    
    public StartupMonitor(SpringApplication app, String[] args) {}
    
    @Override
    public void starting(ConfigurableBootstrapContext bootstrapContext) {
        System.out.println("应用开始启动");
    }
    
    @Override
    public void environmentPrepared(ConfigurableBootstrapContext bootstrapContext, 
                                  ConfigurableEnvironment environment) {
        System.out.println("环境准备完成");
    }
    
    // 其他生命周期方法...
}

注册方式:

在META-INF/spring.factories中:

org.springframework.boot.SpringApplicationRunListener=com.example.StartupMonitor

五、条件化初始化

1. 基于Profile的初始化

@Profile("dev")
@Component
public class DevDataLoader implements CommandLineRunner {
    
    @Override
    public void run(String... args) {
        System.out.println("加载开发环境测试数据");
    }
}

2. 基于条件的Bean创建

@Configuration
public class ConditionalInitConfig {
    
    @Bean
    @ConditionalOnProperty(name = "app.init-sample-data", havingValue = "true")
    public CommandLineRunner sampleDataLoader() {
        return args -> System.out.println("加载示例数据");
    }
}

六、初始化方法对比

方法执行时机适用场景顺序控制访问Spring上下文
ApplicationContextInitializer最早阶段环境准备有限访问
@PostConstructBean初始化单个Bean初始化完全访问
ApplicationRunner启动中期通用初始化支持完全访问
CommandLineRunner启动中期命令行相关初始化支持完全访问
ApplicationReadyEvent最后阶段安全的后启动操作完全访问

七、最佳实践建议

  • 简单初始化:使用@PostConstruct或InitializingBean
  • 复杂初始化:使用CommandLineRunner/ApplicationRunner
  • 环境准备阶段:使用ApplicationContextInitializer
  • 完全启动后操作:监听ApplicationReadyEvent

避免事项:

  • 不要在启动时执行长时间阻塞操作
  • 谨慎处理ContextRefreshedEvent(可能被触发多次)
  • 确保初始化代码是幂等的

八、高级应用示例

1. 异步初始化

@Component
public class AsyncInitializer {
    
    @EventListener(ApplicationReadyEvent.class)
    @Async
    public void asyncInit() {
        System.out.println("异步初始化开始");
        // 执行耗时初始化任务
        System.out.println("异步初始化完成");
    }
}

​​​​​​​@Configuration
@EnableAsync
public class AsyncConfig {
    @Bean
    public Executor taskExecutor() {
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        executor.setCorePoolSize(2);
        executor.setMaxPoolSize(5);
        executor.setQueueCapacity(100);
        executor.initialize();
        return executor;
    }
}

2. 初始化失败处理

@Component
public class StartupFailureHandler implements ApplicationListener<ApplicationFailedEvent> {
    
    @Override
    public void onApplicationEvent(ApplicationFailedEvent event) {
        Throwable exception = event.getException();
        System.err.println("应用启动失败: " + exception.getMessage());
        // 发送警报或记录日志
    }
}

3. 多模块初始化协调

public interface StartupTask {
    void execute() throws Exception;
    int getOrder();
}

@Component
public class StartupCoordinator implements ApplicationRunner {
    
    @Autowired
    private List<StartupTask> startupTasks;
    
    @Override
    public void run(ApplicationArguments args) throws Exception {
        startupTasks.stream()
            .sorted(Comparator.comparingInt(StartupTask::getOrder))
            .forEach(task -> {
                try {
                    task.execute();
                } catch (Exception e) {
                    throw new StartupException("启动任务执行失败: " + task.getClass().getName(), e);
                }
            });
    }
}

通过以上多种方式,Spring Boot 提供了非常灵活的启动时初始化机制,开发者可以根据具体需求选择最适合的方法来实现启动时逻辑执行。

以上就是SpringBoot启动时自动执行特定代码的完整指南的详细内容,更多关于SpringBoot执行特定代码的资料请关注脚本之家其它相关文章!

相关文章

  • springboot防止表单重复提交方式

    springboot防止表单重复提交方式

    本文介绍了两种防止SpringBoot应用中表单重复提交的方法:第一种是使用Redis来实现,通过设置键值对和检查唯一标识来防止重复提交;第二种是使用SpringAOP,通过创建切面和自定义注解来统一处理防重复提交,减少重复代码并保持业务逻辑清晰
    2025-12-12
  • Springboot集成Actuator监控功能详解

    Springboot集成Actuator监控功能详解

    这篇文章主要介绍了Springboot集成Actuator监控功能详解,有时候我们想要实时监控我们的应用程序的运行状态,比如实时显示一些指标数据,观察每时每刻访问的流量,或者是我们数据库的访问状态等等,这时候就需要Actuator了,需要的朋友可以参考下
    2023-09-09
  • eclipse创建项目没有dynamic web的解决方法

    eclipse创建项目没有dynamic web的解决方法

    最近上课要用到eclipse,要用到Dynamic web project.但是我下载的版本上没有.接下来就带大家了解 eclipse创建项目没有dynamic web的解决方法,文中有非常详细的图文示例,需要的朋友可以参考下
    2021-06-06
  • Spring整合redis的操作代码

    Spring整合redis的操作代码

    这篇文章主要介绍了Spring整合redis的操作代码,本文通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定参考借鉴价值,需要的朋友可以参考下
    2022-02-02
  • idea中一键自动生成序列化serialVersionUID方式

    idea中一键自动生成序列化serialVersionUID方式

    这篇文章主要介绍了idea中一键自动生成序列化serialVersionUID方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教
    2023-09-09
  • java中JDeps命令使用

    java中JDeps命令使用

    jdeps是一个Java类依赖分析工具,用于分析Java应用程序的依赖情况,包括类、包、模块以及JDK内部API的使用,本文就来详细的介绍一下,感兴趣的可以了解一下
    2024-09-09
  • 详解Java单例模式的实现与原理剖析

    详解Java单例模式的实现与原理剖析

    单例模式是Java中最简单的设计模式之一。这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式。本文将详解单例模式的实现及原理剖析,需要的可以参考一下
    2022-05-05
  • JDK8中String的intern()方法实例详细解读

    JDK8中String的intern()方法实例详细解读

    String字符串在我们日常开发中最常用的,当然还有他的两个兄弟StringBuilder和StringBuilder,接下来通过本文给大家介绍JDK8中String的intern()方法详细解读,需要的朋友可以参考下
    2022-09-09
  • mybatis如何通过接口查找对应的mapper.xml及方法执行详解

    mybatis如何通过接口查找对应的mapper.xml及方法执行详解

    这篇文章主要给大家介绍了利用mybatis如何通过接口查找对应的mapper.xml及方法执行的相关资料,文中通过示例代码介绍的非常详细,对大家具有一定的参考学习价值,需要的朋友们下面跟着小编一起来学习学习吧。
    2017-06-06
  • Java如何获取HttpServletRequest请求参数

    Java如何获取HttpServletRequest请求参数

    我们常需要接口接收第三方推送的数据,由于第三方可能不具备开发能力,我们需要自行解析推送的数据格式,通过HttpServletRequest,我们可以解析字符串、JSON、XML以及文件等多种数据类型,本文介绍了如何在Java中使用HttpServletRequest获取请求参数,感兴趣的朋友一起看看吧
    2024-11-11

最新评论