本文最后更新于 2025-06-09,文章内容可能已经过时。

在 Spring Boot 项目中,如果你希望在项目启动时执行查询数据库的操作(例如初始化数据、校验连接或预加载缓存),可以使用以下几种方式实现:

一:使用 CommandLineRunner 接口

这是最常见的方式之一,适用于简单的启动任务。

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.CommandLineRunner;
import org.springframework.stereotype.Component;

@Component
public class StartupRunner implements CommandLineRunner {

    @Autowired
    private UserRepository userRepository; // 假设你有一个用户仓库接口

    @Override
    public void run(String... args) throws Exception {
        System.out.println("Spring Boot 应用已启动,开始查询数据库...");

        // 执行查询操作
        Long userCount = userRepository.count();
        System.out.println("当前用户表中的记录数: " + userCount);
    }
}

二:使用 ApplicationRunner 接口

CommandLineRunner 类似,但参数是 ApplicationArguments,更便于处理带选项的命令行参数。

import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import org.springframework.stereotype.Component;

@Component
public class MyApplicationRunner implements ApplicationRunner {

    @Autowired
    private UserService userService;

    @Override
    public void run(ApplicationArguments args) throws Exception {
        System.out.println("A应用启动后执行数据库查询...");
        System.out.println("用户数量:" + userService.getUserCount());
    }
}

三:监听 ApplicationReadyEvent 事件

适合需要等待整个上下文完全加载后再执行的任务。

import org.springframework.context.event.EventListener;
import org.springframework.boot.context.event.ApplicationReadyEvent;
import org.springframework.stereotype.Component;

@Component
public class AppStartupRunner {

    private final UserService userService;

    public AppStartupRunner(UserService userService) {
        this.userService = userService;
    }

    @EventListener(ApplicationReadyEvent.class)
    public void onApplicationReady() {
        System.out.println("Q应用完全启动完成,开始查询数据库...");
        System.out.println("用户总数:" + userService.getUserCount());
    }
}

四:通过 @PostConstruct 注解(不推荐用于复杂逻辑)

适用于某个 Bean 初始化完成后执行的方法,但不能保证所有 Bean 都已经初始化完毕。

package com.nn3n.bootdemo.config;

import jakarta.annotation.PostConstruct;
import org.springframework.stereotype.Component;


@Component
public class MyComponent {

    @PostConstruct
    public void init() {
        // 查询数据库操作
        System.err.println("MyComponent init");
    }
}
MyComponent init
MyComponent init
MyComponent init
MyComponent init
2025-06-09T11:14:14.954+08:00  INFO 16136 --- [boot-demo] [  restartedMain] o.s.b.d.a.OptionalLiveReloadServer       : LiveReload server is running on port 35729
2025-06-09T11:14:14.981+08:00  INFO 16136 --- [boot-demo] [  restartedMain] o.s.b.w.embedded.tomcat.TomcatWebServer  : Tomcat started on port 8080 (http) with context path '/'
2025-06-09T11:14:14.989+08:00  INFO 16136 --- [boot-demo] [  restartedMain] c.y.major.bootdemo.BootDemoApplication   : Started BootDemoApplication in 1.276 seconds (process running for 1.863)
A应用启动后执行数据库查询...
A应用启动后执行数据库查询...
A应用启动后执行数据库查询...
A应用启动后执行数据库查询...
A应用启动后执行数据库查询...
Spring Boot 应用已启动,开始查询数据库...
Spring Boot 应用已启动,开始查询数据库...
Spring Boot 应用已启动,开始查询数据库...
Q应用完全启动完成,开始查询数据库...
Q应用完全启动完成,开始查询数据库...
Q应用完全启动完成,开始查询数据库...
Q应用完全启动完成,开始查询数据库...
Q应用完全启动完成,开始查询数据库...

五、总结对比

方法适用场景是否推荐
CommandLineRunner简单任务、脚本式执行✅ 推荐
ApplicationRunner需要处理命令行参数✅ 推荐
ApplicationReadyEvent需要等整个应用启动完成✅ 推荐
@PostConstruct局部初始化任务❌ 不推荐用于数据库操作

六、提示事项

  • 启动时避免执行耗时过长的操作,以免影响启动性能。
  • 如果需要异步执行,可以加上 @Async 注解并启用异步支持。