SpringBoot启动流程分析之命令行参数args的封装解析(三)
目录
文章目录
- SpringBoot启动流程分析之命令行参数args的封装解析(三)
- 1、DefaultApplicationArguments构造方法
- 2、参数解析
- 3、测试验证
流程分析发布ApplicationStartingEvent后就是封装args参数。
org.springframework.boot.SpringApplication#run(java.lang.String…)
public ConfigurableApplicationContext run(String... args) {
...
try {
// 开始分析...
ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
ConfigurableEnvironment environment = prepareEnvironment(listeners, applicationArguments);
configureIgnoreBeanInfo(environment);
Banner printedBanner = printBanner(environment);
context = createApplicationContext();
exceptionReporters = getSpringFactoriesInstances(SpringBootExceptionReporter.class,
new Class[] { ConfigurableApplicationContext.class }, context);
prepareContext(context, environment, listeners, applicationArguments, printedBanner);
refreshContext(context);
afterRefresh(context, applicationArguments);
stopWatch.stop();
if (this.logStartupInfo) {
new StartupInfoLogger(this.mainApplicationClass).logStarted(getApplicationLog(), stopWatch);
}
listeners.started(context);
callRunners(context, applicationArguments);
}
catch (Throwable ex) {
handleRunFailure(context, ex, exceptionReporters, listeners);
throw new IllegalStateException(ex);
}
...
}
1、DefaultApplicationArguments构造方法
可以看到args参数在构造方法中在作为参数放到了DefaultApplicationArguments的静态内部类Source的构造方法中进一步封装,至于下面的全局变量args放的就是原始的args参数。可以通过getSourceArgs方法得到。
public class DefaultApplicationArguments implements ApplicationArguments {
private final Source source;
private final String[] args;
public DefaultApplicationArguments(String[] args) {
Assert.notNull(args, "Args must not be null");
this.source = new Source(args);
this.args = args;
}
private static class Source extends SimpleCommandLinePropertySource {
Source(String[] args) {
super(args);
}
@Override
public List<String> getNonOptionArgs() {
return super.getNonOptionArgs();
}
@Override
public List<String> getOptionValues(String name) {
return super.getOptionValues(name);
}
}
// 其它方法忽略...
2、参数解析
类图
在Source的父类SimpleCommandLinePropertySource的构造方法中new了一个SimpleCommandLineArgsParser对象,然后调用parse()方法解析参数,如下。
public class SimpleCommandLinePropertySource extends CommandLinePropertySource<CommandLineArgs> {
/**
* Create a new {@code SimpleCommandLinePropertySource} having the default name
* and backed by the given {@code String[]} of command line arguments.
* @see CommandLinePropertySource#COMMAND_LINE_PROPERTY_SOURCE_NAME
* @see CommandLinePropertySource#CommandLinePropertySource(Object)
*/
public SimpleCommandLinePropertySource(String... args) {
super(new SimpleCommandLineArgsParser().parse(args));
}
}
class SimpleCommandLineArgsParser {
/**
* Parse the given {@code String} array based on the rules described {@linkplain
* SimpleCommandLineArgsParser above}, returning a fully-populated
* {@link CommandLineArgs} object.
* @param args command line arguments, typically from a {@code main()} method
*/
public CommandLineArgs parse(String... args) {
//创建CommandLineArgs对象
CommandLineArgs commandLineArgs = new CommandLineArgs();
for (String arg : args) {
if (arg.startsWith("--")) {
//如果是就截取,截取长度是参数长度,如果命令是--spring,那么就从s开始截取,包括s
String optionText = arg.substring(2, arg.length());
String optionName;
String optionValue = null;
//如果匹配到了=号,截取=号左边做optionName,右边做optionValue
if (optionText.contains("=")) {
optionName = optionText.substring(0, optionText.indexOf('='));
optionValue = optionText.substring(optionText.indexOf('=')+1, optionText.length());
}
else {
//如果没有=号,optionName 直接就是截取的optionText
optionName = optionText;
}
if (optionName.isEmpty() || (optionValue != null && optionValue.isEmpty())) {
throw new IllegalArgumentException("Invalid argument syntax: " + arg);
}
//这里将解析的参数添加到上面创建的CommandLineArgs对象中,该对象中有一个Map<String, List<String>>来存放
commandLineArgs.addOptionArg(optionName, optionValue);
}
else {
commandLineArgs.addNonOptionArg(arg);
}
}
return commandLineArgs;
}
}
回过头继续跟踪到父类CommandLinePropertySource构造方法,这里又传了一个字符串"commandLineArgs"到父类构造,为默认name。
通过以上的类图关系,最后是赋值给了PropertySource的name和source。该类用来存放key/value属性对的抽象基类。value可以是任意类型。到这DefaultApplicationArguments对象的创建流程就走完了。
3、测试验证
可以验证一下。右键->run as->run configurations,添加一个命令行参数。
@SpringBootApplication
public class Application {
public static void main(String[] args) {
// SpringApplication.run(Application.class, args);
SpringApplication application = new SpringApplication(Application.class);
ConfigurableApplicationContext context = application.run(args);
ApplicationArguments arguments = context.getBean(ApplicationArguments.class);
System.out.println(context.getEnvironment().getPropertySources().get("commandLineArgs").getProperty("spring.config.location"));
System.out.println("name:"+arguments.getOptionNames()+" , value:"+arguments.getOptionValues("spring.config.location"));
context.close();
}
}
补充一下:命令行参数在cmd中添加如下,先在项目根目录执行mvn clean install ,然后到target目录或者在jar包前面加上target目录都行,执行图片中的命令运行, 图片是从我后面文章复制过来的,主要是说明命令行参数在cmd中怎么加