1. 概述

Spring Boot 以简化 Web 应用开发而闻名,但它的能力远不止于此。它还提供了许多适用于非 Web 场景的工具。

本文将演示如何使用 Kotlin 编写一个基于控制台的 Spring Boot 应用,核心是使用 CommandLineRunner 接口来实现启动后执行逻辑。

2. 依赖配置

要创建一个 Spring Boot 控制台应用,我们只需要引入 spring-boot-starter 即可。以下是使用 Gradle 和 Maven 的配置方式:

Gradle:

implementation("org.springframework.boot:spring-boot-starter")

Maven:

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter</artifactId>
</dependency>

3. CommandLineRunner 接口

CommandLineRunner 是一个函数式接口,它定义了一个 run 方法,接收原始的 String[] 参数。Spring Boot 在启动完成后会自动调用所有实现了该接口的 Bean 的 run 方法。

@FunctionalInterface
public interface CommandLineRunner {
    void run(String... args) throws Exception;
}

接下来我们让主类实现这个接口:

@SpringBootApplication
class SpringBootConsoleApplication : CommandLineRunner {

    private val log = LoggerFactory.getLogger(SpringBootConsoleApplication::class.java)

    override fun run(vararg args: String?) {
        args.forEach { log.info("Application args: $it") }
    }
}

fun main(args: Array<String>) {
    runApplication<SpringBootConsoleApplication>(*args)
}

运行时传入参数 hello,控制台会输出:

INFO 61619 --- [main] c.b.c.SpringBootConsoleApplicationKt     : Starting SpringBootConsoleApplicationKt
INFO 61619 --- [main] c.b.c.SpringBootConsoleApplicationKt     : No active profile set, falling back to 1 default profile: "default"
INFO 61619 --- [main] c.b.c.SpringBootConsoleApplicationKt     : Started SpringBootConsoleApplicationKt in 1.153 seconds (JVM running for 1.967)
INFO 61619 --- [main] c.b.c.SpringBootConsoleApplication       : Application args: hello

可以看到,run() 方法是在 Spring Boot 启动完成后执行的。

4. 与用户交互(读取输入)

Kotlin 提供了多种方式从控制台读取输入,其中一种简单的方式是使用 readlnOrNull() 方法:

override fun run(vararg args: String?) {
    log.info("Please type your name:")
    val name = readlnOrNull()
    log.info("Hello $name. This is a Spring Boot Console Application")
}

运行后程序会等待用户输入:

INFO 62997 --- [main] c.b.c.SpringBootConsoleApplicationKt     : Starting SpringBootConsoleApplicationKt using Java 17.0.4 on Fabios-MacBook-Pro.local with PID 62997 (/Users/fabiomiyasato/dev/git/kotlin-tutorials/spring-boot-kotlin-2/target/classes started by fabiomiyasato in /Users/fabiomiyasato/dev/git/kotlin-tutorials/spring-boot-kotlin-2)
INFO 62997 --- [main] c.b.c.SpringBootConsoleApplicationKt     : No active profile set, falling back to 1 default profile: "default"
INFO 62997 --- [main] c.b.c.SpringBootConsoleApplicationKt     : Started SpringBootConsoleApplicationKt in 1.217 seconds (JVM running for 1.687)
INFO 62997 --- [main] c.b.c.SpringBootConsoleApplication       : Please type your name:

输入后按回车,程序继续执行并结束:

new user
INFO 62997 --- [main] c.b.c.SpringBootConsoleApplication       : Hello new user. This is a Spring Boot Console Application

5. 多个 CommandLineRunner 的执行顺序

大多数控制台应用只需要一个 CommandLineRunner 实现。如果需要多个,推荐将它们定义为 @Component 而不是放在主类中。

此时可以使用 Spring 的 @Order 注解来控制执行顺序:

@Component
@Order(0)
class CommandLineFirstComponent : CommandLineRunner {

    private val log = LoggerFactory.getLogger(CommandLineFirstComponent::class.java)

    override fun run(vararg args: String?) {
        log.info(CommandLineFirstComponent::class.simpleName)
    }
}

第二个组件:

@Component
@Order(1)
class CommandLineSecondComponent : CommandLineRunner {

    private val log = LoggerFactory.getLogger(CommandLineSecondComponent::class.java)

    override fun run(vararg args: String?) {
        log.info(CommandLineSecondComponent::class.simpleName)
    }
}

这两个组件都实现了 CommandLineRunner 接口,并使用了 @Component 注解,以便 Spring 自动注册为 Bean。

运行后输出如下:

INFO 62516 --- [main] c.b.c.SpringBootConsoleApplicationKt     : Starting SpringBootConsoleApplicationKt
INFO 62516 --- [main] c.b.c.SpringBootConsoleApplicationKt     : Started SpringBootConsoleApplicationKt in 1.182 seconds (JVM running for 1.668)
INFO 62516 --- [main] c.b.c.CommandLineFirstComponent          : CommandLineFirstComponent
INFO 62516 --- [main] c.b.c.CommandLineSecondComponent         : CommandLineSecondComponent

✅ 可以看到 CommandLineFirstComponent 确实先于 CommandLineSecondComponent 执行。

6. 总结

控制台应用在很多场景下都非常实用。本文介绍了如何使用 Spring Boot 构建 Kotlin 控制台应用,并利用 CommandLineRunner 实现启动逻辑。

虽然 Spring Boot 本身是为 Web 场景设计的,但在非 Web 场景下也能发挥其依赖注入、组件管理等优势。

⚠️ 如果你计划构建一个更复杂的命令行接口(CLI),建议考虑使用 Spring Shell,它提供了更结构化的注解方式来定义命令。

完整的源码可在 GitHub 上找到。


原始标题:Creating a Spring Boot Console Application With Kotlin