背景
在最近的一个项目中,因为开发环境和测试环境的配置差异很大,就想着不同环境做不同的配置,在启动时候选择具体的环境就可以了。配置如下图:
实操
配置完成后commit,push,合并到master(听说10.1后就会是main了),测试环境拉代码build,感觉稳如老狗,结果却是出乎意料,spring.proflies.active=dev没起作用,自己在本地电脑打包以后,用命令行启动,发现本应是
The following profiles are active: dev
结果却是
No active profile set, falling back to default profiles: default
这就说明spring.proflies.active这个变量并没有传递到启动的环境参数中,这是怎么回事了?这个问题在我的第一个项目中也遇到过,当时是稀里糊涂的就过去了,也没有细究,这次我决定一定要一劳永逸的解决这个问题。
解决
于是打开Google,开启查找模式,经历了多次的尝试过后,最后找见原因所在,在spring应用的入口处的run方法没有传递参数导致的,赶紧在run方法加上参数,再进行尝试,达到预想的结果。
之前的代码
@SpringBootApplication
public class MyApplication {
public static void main(String[] args) {
SpringApplication.run(MyApplication.class);
}
}
加入参数后
@SpringBootApplication
public class MyApplication {
public static void main(String[] args) {
SpringApplication.run(MyApplication.class, args);
}
}
探究
public static ConfigurableApplicationContext run(Class<?> primarySource, String... args) {
return run(new Class[]{primarySource}, args);
}
public static ConfigurableApplicationContext run(Class<?>[] primarySources, String[] args) {
//run函数包含参数
return (new SpringApplication(primarySources)).run(args);
}
SpringApplication.run方法包含两个参数,第一个是primarySource,接受一个容器的配置类,也可以说是程序的入口类,第二个参数args就是我丢掉的命令行参数,命令行参数传入到SpringApplication中,用命令行启动时,依据参数加载对应的配置。
下面是SpringApplication的构造函数(new SpringApplication(primarySources))。
主要是
/**
* Run the Spring application, creating and refreshing a new
* {@link ApplicationContext}.
* @param args the application arguments (usually passed from a Java main method)
* @return a running {@link ApplicationContext}
*/
public ConfigurableApplicationContext run(String... args) {
StopWatch stopWatch = new StopWatch();
stopWatch.start();
ConfigurableApplicationContext context = null;
Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList<>();
configureHeadlessProperty();
SpringApplicationRunListeners listeners = getRunListeners(args);
listeners.starting();
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);
}
try {
listeners.running(context);
}
catch (Throwable ex) {
handleRunFailure(context, ex, exceptionReporters, null);
throw new IllegalStateException(ex);
}
return context;
}
ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
DefaultApplicationArguments构造方法
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);
}
}
}
args参数在构造方法中在作为参数放到了DefaultApplicationArguments的静态内部类Source的构造方法中进一步封装,至于下面的全局变量args放的就是原始的args参数。可以通过getSourceArgs方法得到。
参数解析
在父类SimpleCommandLinePropertySource的构造方法中new了一个SimpleCommandLineArgsParser对象,然后调用parse()方法解析参数
public CommandLineArgs parse(String... args) {
CommandLineArgs commandLineArgs = new CommandLineArgs();
String[] var3 = args;
int var4 = args.length;
for(int var5 = 0; var5 < var4; ++var5) {
String arg = var3[var5];
if (arg.startsWith("--")) {
String optionText = arg.substring(2);
String optionValue = null;
int indexOfEqualsSign = optionText.indexOf(61);
String optionName;
if (indexOfEqualsSign > -1) {
optionName = optionText.substring(0, indexOfEqualsSign);
optionValue = optionText.substring(indexOfEqualsSign + 1);
} else {
optionName = optionText;
}
if (optionName.isEmpty()) {
throw new IllegalArgumentException("Invalid argument syntax: " + arg);
}
commandLineArgs.addOptionArg(optionName, optionValue);
} else {
commandLineArgs.addNonOptionArg(arg);
}
}
return commandLineArgs;
}