Spring Boot 2.1.1(九)启动流程分析之args参数的封装解析
接上篇博客Spring Boot 2.1.1(八)启动流程分析之ApplicationStartingEvent事件的发布监听流程
目录
1、DefaultApplicationArguments构造方法
流程分析
发布ApplicationStartingEvent后就是封装args参数。
public ConfigurableApplicationContext run(String... args) {
....
//本篇博客从本行开始记录
try {
ApplicationArguments applicationArguments = new DefaultApplicationArguments(
args);
//本篇内容记录到这,后续更新
....
}
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、参数解析
类图。
在父类SimpleCommandLinePropertySource的构造方法中new了一个SimpleCommandLineArgsParser对象,然后调用parse()方法解析参数,如下。
public SimpleCommandLinePropertySource(String... args) {
super(new SimpleCommandLineArgsParser().parse(args));
}
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();
}
}
成功!