告别繁琐脚本!用 Spring Boot 优雅编写命令行应用

6次阅读
没有评论

在日常开发和运维工作中,我们经常需要编写命令行脚本处理批量任务、数据初始化、定时运维等工作。传统的 Shell/Python 脚本虽然轻便,但在依赖管理、代码复用、企业级功能(数据库操作、缓存、消息队列) 上力不从心。

Spring Boot完全可以用来开发命令行脚本!它继承了 Spring 生态的所有优势:自动配置、依赖注入、开箱即用的中间件集成,还能打包成单一可执行 JAR,跨平台运行,完美解决了传统脚本的痛点。

今天就带大家从零开始,用 Spring Boot 编写专业的命令行脚本!


一、为什么用 Spring Boot 写命令行脚本?

  1. 零配置:自动配置,无需繁琐的 XML / 配置文件
  2. 生态强大:无缝集成 MySQL、Redis、MQ、MyBatis 等企业级组件
  3. 代码复用:直接复用项目中的 Service、DAO、工具类
  4. 打包便捷:打包成单个 JAR,java -jar 直接运行,无环境依赖
  5. 健壮性:支持日志、异常处理、参数校验、退出码等专业特性
  6. 无冗余:可以完全不启动 Web 容器,纯命令行运行,轻量高效

二、环境准备

  • JDK 8+
  • Maven/Gradle
  • IDEA/Eclipse
  • Spring Boot 2.x/3.x(本文用 3.x)

核心:不要引入 Web 依赖,命令行脚本不需要启动 Tomcat!


三、快速入门:第一个 Spring Boot 命令行脚本

1. 创建 Spring Boot 项目

通过 Spring Initializr 创建项目,仅选择核心依赖:

xml

<!-- 仅需Spring Boot核心启动器,无Web依赖 -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter</artifactId>
</dependency>

<!-- 测试依赖(可选) -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-test</artifactId>
    <scope>test</scope>
</dependency>

2. 核心:实现命令行执行接口

Spring Boot 提供两个核心接口用于编写命令行逻辑,项目启动后会自动执行:

  • CommandLineRunner:最基础,参数为字符串数组
  • ApplicationRunner:进阶版,支持优雅的参数解析

最简示例(CommandLineRunner)

java

运行

import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.stereotype.Component;

// 启动类
@SpringBootApplication
public class CommandLineScriptApplication {
    public static void main(String[] args) {
        SpringApplication.run(CommandLineScriptApplication.class, args);
    }
}

// 命令行执行逻辑
@Component
public class SimpleScript implements CommandLineRunner {

    /**
     * 项目启动后自动执行该方法
     * @param args 命令行传入的参数
     */
    @Override
    public void run(String... args) throws Exception {
        System.out.println("========= Spring Boot 命令行脚本执行成功 =========");
        System.out.println("传入参数:" + String.join(", ", args));
    }
}

3. 运行脚本

方式 1:IDE 直接运行

启动项目,控制台直接输出执行结果。

方式 2:打包为可执行 JAR 运行

bash

运行

# 打包
mvn clean package -DskipTests

# 运行脚本(带参数)
java -jar target/command-line-script-0.0.1-SNAPSHOT.jar hello springboot

输出结果

plaintext

========= Spring Boot 命令行脚本执行成功 =========
传入参数:hello, springboot

四、核心接口对比:CommandLineRunner vs ApplicationRunner

1. CommandLineRunner

  • 优点:简单直接
  • 缺点:参数是原生字符串数组,解析复杂参数(如--name=test --age=18)需要手动处理

2. ApplicationRunner(推荐)

  • 优点:内置ApplicationArguments对象,自动解析命名参数、选项参数、无名称参数,开发更高效

示例:优雅解析命令行参数

java

运行

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

@Component
public class AdvancedScript implements ApplicationRunner {

    @Override
    public void run(ApplicationArguments args) throws Exception {
        System.out.println("========= 进阶参数解析 =========");

        // 1. 获取所有原生参数
        System.out.println("所有参数:" + args.getSourceArgs());

        // 2. 获取无名称参数(直接传的值)
        System.out.println("无名称参数:" + args.getNonOptionArgs());

        // 3. 获取命名参数(--key=value格式)
        if (args.containsOption("name")) {
            System.out.println("参数name:" + args.getOptionValues("name").get(0));
        }
        if (args.containsOption("age")) {
            System.out.println("参数age:" + args.getOptionValues("age").get(0));
        }
    }
}

运行命令

bash

运行

java -jar xxx.jar --name=张三 --age=20 测试参数

输出

plaintext

========= 进阶参数解析 =========
所有参数:[--name=张三, --age=20, 测试参数]
无名称参数:[测试参数]
参数name:张三
参数age:20

五、进阶实战:企业级命令行脚本

实际开发中,我们需要依赖注入、业务逻辑、数据库操作等功能,Spring Boot 可以无缝支持!

场景:数据初始化命令行脚本

  1. 定义 Service 层

java

运行

@Service
public class DataInitService {
    public void initData() {
        // 模拟数据库初始化
        System.out.println("执行数据初始化:插入默认用户、配置数据...");
    }
}
  1. 命令行类注入 Service

java

运行

@Component
public class DataInitScript implements ApplicationRunner {

    // 依赖注入,直接复用项目业务代码
    private final DataInitService dataInitService;

    // 构造器注入(Spring 4.3+推荐)
    public DataInitScript(DataInitService dataInitService) {
        this.dataInitService = dataInitService;
    }

    @Override
    public void run(ApplicationArguments args) {
        System.out.println("开始执行数据初始化脚本...");
        dataInitService.initData();
        System.out.println("数据初始化完成!");
    }
}
  1. 运行效果

plaintext

开始执行数据初始化脚本...
执行数据初始化:插入默认用户、配置数据...
数据初始化完成!

六、高级技巧:生产级必备功能

1. 多脚本执行顺序

如果有多个Runner,用@Order注解指定执行顺序(数字越小,优先级越高):

java

运行

@Component
@Order(1) // 第一个执行
public class FirstScript implements CommandLineRunner {}

@Component
@Order(2) // 第二个执行
public class SecondScript implements CommandLineRunner {}

2. 自定义退出码

命令行脚本通常需要返回退出码(0 = 成功,非 0 = 失败),方便 Shell 脚本调用:

java

运行

import org.springframework.boot.ExitCodeGenerator;
import org.springframework.stereotype.Component;

@Component
public class ExitCodeScript implements CommandLineRunner, ExitCodeGenerator {

    private int exitCode;

    @Override
    public void run(String... args) {
        try {
            // 执行业务逻辑
            exitCode = 0;
        } catch (Exception e) {
            exitCode = 1;
            throw e;
        }
    }

    // 自定义退出码
    @Override
    public int getExitCode() {
        return exitCode;
    }
}

3. 配置文件支持

和普通 Spring Boot 项目一样,支持application.yml/application.properties配置:

yaml

# application.yml
script:
  name: 数据初始化脚本
  max-count: 1000

直接用@Value注入使用:

java

运行

@Value("${script.name}")
private String scriptName;

4. 日志优化

替换System.out为专业日志框架(Spring Boot 默认集成 Logback):

java

运行

import lombok.extern.slf4j.Slf4j;

@Slf4j
@Component
public class LogScript implements CommandLineRunner {
    @Override
    public void run(String... args) {
        log.info("脚本开始执行,参数:{}", args);
        log.error("执行异常", new RuntimeException("测试错误"));
    }
}

七、打包与部署(一键运行)

Spring Boot 命令行脚本打包方式和普通项目完全一致

bash

运行

# Maven打包
mvn clean package -DskipTests

# 运行
java -jar xxx.jar [参数]

✅ 优势:

  • 单一 JAR 文件,无依赖冲突
  • 跨平台(Windows/Linux/Mac 都能运行)
  • 可配合 Linux 定时任务(crontab)实现自动化执行

八、避坑指南

  1. 不要引入 spring-boot-starter-web:会启动 Tomcat Web 容器,浪费资源
  2. 禁止长时间阻塞:命令行脚本执行完成后会自动退出,不要写死循环
  3. 参数校验:使用ApplicationArguments判断参数是否存在,避免空指针
  4. 异常处理:必须捕获异常,保证脚本健壮性

九、适用场景

Spring Boot 命令行脚本非常适合以下工作:

  • 数据初始化、数据迁移、数据清洗
  • 定时运维脚本(配合 crontab)
  • 批量导入 / 导出文件
  • 企业内部小工具
  • 项目启动前的预处理任务

总结

Spring Boot 让命令行脚本开发告别了「简陋」,走向了工程化、标准化、企业级。它既保留了命令行脚本的轻便,又拥有 Spring 生态的强大能力,是后端开发和运维的绝佳工具。

只需要实现CommandLineRunner/ApplicationRunner接口,就能快速开发出专业的命令行应用,打包即用,快来试试吧!


核心知识点回顾

  1. 核心接口:CommandLineRunner(基础)、ApplicationRunner(推荐,参数解析更优雅)
  2. 无 Web 依赖:纯命令行运行,轻量高效
  3. 无缝集成:依赖注入、Service 复用、配置、日志全支持
  4. 一键打包:单一 JAR,跨平台直接运行
  5. 生产级特性:执行顺序、退出码、异常处理、参数校验
正文完
可以使用微信扫码关注公众号(ID:xzluomor)
post-qrcode
 0
评论(没有评论)
验证码