在 Spring Boot 工程中获取命令行属性,核心是利用 Spring 框架对命令行参数的封装(比原生 Java 更便捷),同时兼容 Spring Boot 的配置优先级规则。以下是 不同场景的完整实现方式,涵盖核心需求:
一、核心概念:Spring Boot 中的命令行属性
Spring Boot 会将命令行传入的参数(以 -- 开头)解析为 配置属性 ,并纳入 Spring 的 Environment 体系,优先级高于配置文件(如 application.yml)。
- 格式:
java -jar app.jar --server.port=8081 --custom.name=test - 非
--开头的普通参数:也可获取(如java -jar app.jar arg1 arg2)。
二、场景 1:获取 -- 开头的命令行配置属性(最常用)
这是 Spring Boot 推荐的方式,命令行参数会被解析为 Spring 环境属性,可通过以下 3 种方式获取:
方式 1:通过 Environment 直接获取
注入 org.springframework.core.env.Environment,调用 getProperty() 获取属性值:
java
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.env.Environment;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class CmdPropertyController {
@Autowired
private Environment environment;
@GetMapping("/get-cmd-prop")
public String getCmdProperty() {
// 获取命令行传入的 --server.port
String port = environment.getProperty("server.port");
// 获取自定义命令行属性 --custom.name
String customName = environment.getProperty("custom.name");
return "port: " + port + ", customName: " + customName;
}
}
方式 2:通过 @Value 注解注入
直接将命令行属性注入到变量中,简化代码:
java
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class CmdValueController {
// 注入命令行的 --server.port(无默认值时,未传则报错)
@Value("${server.port}")
private String serverPort;
// 注入自定义属性,设置默认值(未传则用默认值)
@Value("${custom.name:defaultName}")
private String customName;
@GetMapping("/get-cmd-value")
public String getCmdValue() {
return "serverPort: " + serverPort + ", customName: " + customName;
}
}
方式 3:绑定到配置类(推荐复杂属性)
如果有多个自定义命令行属性,可绑定到 @ConfigurationProperties 配置类,更易维护:
java
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
// 绑定前缀为 "custom" 的命令行属性
@Component
@ConfigurationProperties(prefix = "custom")
public class CustomCmdProperties {
private String name;
private Integer age;
// 生成 getter/setter
public String getName() { return name; }
public void setName(String name) { this.name = name; }
public Integer getAge() { return age; }
public void setAge(Integer age) { this.age = age; }
}
使用时注入配置类:
java
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class CmdConfigController {
@Autowired
private CustomCmdProperties customCmdProperties;
@GetMapping("/get-cmd-config")
public String getCmdConfig() {
return "customName: " + customCmdProperties.getName()
+ ", customAge: " + customCmdProperties.getAge();
}
}
测试命令:java -jar app.jar --custom.name=test --custom.age=20
三、场景 2:获取非 -- 开头的普通命令行参数
如果传入的是普通参数(无 -- 前缀,如 java -jar app.jar arg1 arg2),需通过 Spring Boot 的 ApplicationArguments 获取:
java
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.ApplicationArguments;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class CommonArgsController {
// 注入 ApplicationArguments,Spring Boot 自动封装命令行参数
@Autowired
private ApplicationArguments applicationArguments;
@GetMapping("/get-common-args")
public String getCommonArgs() {
// 获取所有非 -- 开头的普通参数(如 arg1、arg2)
String[] nonOptionArgs = applicationArguments.getNonOptionArgs().toArray(new String[0]);
// 获取所有 -- 开头的选项参数名(如 server.port、custom.name)
String[] optionNames = applicationArguments.getOptionNames().toArray(new String[0]);
// 获取某个选项参数的值(如 --custom.name=test → [test])
String customName = applicationArguments.getOptionValues("custom.name").get(0);
return "普通参数:" + String.join(",", nonOptionArgs)
+ ",选项参数名:" + String.join(",", optionNames)
+ ",custom.name:" + customName;
}
}
测试命令:java -jar app.jar arg1 arg2 --custom.name=test
输出:普通参数:arg1,arg2,选项参数名:custom.name,custom.name:test
四、场景 3:启动类中直接获取命令行参数
如果需要在 Spring Boot 启动阶段(上下文初始化前)获取命令行参数,可在 main 方法中处理:
java
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class CmdDemoApplication {
public static void main(String[] args) {
// 1. 原生 Java 方式:直接遍历 main 方法的 args 数组
System.out.println("原生命令行参数:");
for (String arg : args) {
System.out.println(arg);
}
// 2. 启动 Spring 上下文,并传入参数(必须)
var applicationContext = SpringApplication.run(CmdDemoApplication.class, args);
// 3. 启动后从上下文获取 Environment,解析 -- 开头的属性
var environment = applicationContext.getEnvironment();
String port = environment.getProperty("server.port");
System.out.println("启动后获取 server.port:" + port);
}
}
五、关键注意事项
-
配置优先级 :命令行属性(
--xxx)优先级最高,会覆盖application.yml、环境变量等配置; -
参数格式 :
- 选项参数必须以
--开头(如--key=value或--key value); - 多个值的参数:
--custom.list=1 --custom.list=2,可通过applicationArguments.getOptionValues("custom.list")获取列表;
- 选项参数必须以
-
特殊字符处理 :如果参数包含空格/特殊字符,需用引号包裹(如
--custom.desc="hello world"); -
禁用命令行参数 :如果不想让命令行参数覆盖配置,可在启动类中设置:
javaSpringApplication application = new SpringApplication(CmdDemoApplication.class); application.setAddCommandLineProperties(false); // 禁用命令行参数解析 application.run(args);
六、常用工具方法(封装获取)
java
import org.springframework.boot.ApplicationArguments;
import org.springframework.core.env.Environment;
import org.springframework.stereotype.Component;
@Component
public class CmdPropertyUtil {
private final Environment environment;
private final ApplicationArguments applicationArguments;
// 构造器注入
public CmdPropertyUtil(Environment environment, ApplicationArguments applicationArguments) {
this.environment = environment;
this.applicationArguments = applicationArguments;
}
// 获取单个命令行配置属性(带默认值)
public String getCmdProperty(String key, String defaultValue) {
return environment.getProperty(key, defaultValue);
}
// 获取普通命令行参数列表(非 -- 开头)
public String[] getCommonArgs() {
return applicationArguments.getNonOptionArgs().toArray(new String[0]);
}
// 判断是否包含某个选项参数(如 --debug)
public boolean hasOption(String optionName) {
return applicationArguments.containsOption(optionName);
}
}
以上是 Spring Boot 工程中获取命令行属性的全场景方案,可根据实际需求(如启动时处理、运行时注入、复杂属性绑定)选择对应方式。