目录

前言

一、激活指定的配置文件

1.1通过java运行参数进行指定

1.2 通过在application.properties中添加配置项

二、修改具体的配置属性

三、-Dkey=value 生效的原因

小结:

总结




前言

        在使用springboot项目进行开发与部署时,很多时候需要多种环境(配置文件)进行切换,如果我们每次切换环境时都通过对指定的文件中的属性值进行更改,就有些麻烦。这时候我们可以通过激活指定的配置文件来切换环境。


一、激活指定的配置文件

激活指定配置文件有两种方式,一种是通过配置java运行参数指定,一种是通过配置application.properties属性完成

1.1通过java运行参数进行指定

     具体命令如下:

java -jar -Dspring.profiles.active=dev demo.jar

   说明: 

   dev 是在resources目录下的配置文件application-dev.properties的后缀,支持properties和yaml格式。

    需要注意的是,我们会一般会把配置文件命名为application-dev.properties,application-test.properties,application-pro.properties,实际上spring并没有对后缀进行限制,如application-dev1.properties,配置文件通过java -jar -Dspring.profiles.active=dev1 demo.jar命令也是可以正常生效的。如果我们不指定 -Dspring.profiles.active属性或默认使用application.properties

1.2 通过在application.properties中添加配置项

spring.profiles.active=dev

 说明:

  springboot在启动时会读取application.properties配置文件内容。通过配置spring.profiles.active 也可以达到相同的效果。

二、修改具体的配置属性

在某些情况下需要修改配置文件中已经配置好的配置文件,可以通过命令:

java -jar -Dkey=value demo.jar

小结:

     通过前面的内容可以看到 在java -jar 后面 加 -Dkey=value 的方式可以对spring中的配置进行赋值或修改。那么,springboot到底是怎么做到的呢。有兴趣的朋友可以继续往下看

三、-Dkey=value 生效的原因

要弄清这个原因,我们还要从springBoot启动的源头(main方法)说起。

我们启动一个springBoot项目,一般都会通过run方法进行启动,如下所示:SpringApplication.run(SpringApplicationTest.class, args);现在我们就通过源码查看一下run方法里做了哪些事情。 

首先进入我们视线的是SpringApplication中的run方法,其中有一个prepareEnvironment方法引起了我们的注意,通过方法名和返回参数我猜测到这个方法的作用可能是初始化一个运行所需的配置环境。

public ConfigurableApplicationContext run(String... args) {
		StopWatch stopWatch = new StopWatch();
		stopWatch.start();
		ConfigurableApplicationContext context = null;
		configureHeadlessProperty();
		SpringApplicationRunListeners listeners = getRunListeners(args);
		listeners.starting();
		try {
			ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
			ConfigurableEnvironment environment = prepareEnvironment(listeners, applicationArguments); // 初始化配置环境
			configureIgnoreBeanInfo(environment);
			//.....省略若干行代码
			}
			listeners.started(context);
			callRunners(context, applicationArguments);
		}
		// ...... 省略若干行代码
		return context;
	}

现在我们到prepareEnvironment方法内部接着往下看, getOrCreateEnvironment方法的语义翻译是准备一个环境,看来这个方法是获取配置的关键方法。

private ConfigurableEnvironment prepareEnvironment(SpringApplicationRunListeners listeners,
			ApplicationArguments applicationArguments) {
		// Create and configure the environment
		ConfigurableEnvironment environment = getOrCreateEnvironment();
		configureEnvironment(environment, applicationArguments.getSourceArgs());
		ConfigurationPropertySources.attach(environment);
		listeners.environmentPrepared(environment);
		bindToSpringApplication(environment);
		if (!this.isCustomEnvironment) {
			environment = new EnvironmentConverter(getClassLoader()).convertEnvironmentIfNecessary(environment,
					deduceEnvironmentClass());
		}
		ConfigurationPropertySources.attach(environment);
		return environment;
	}

进入getOrCreateEnvironment方法后发现,方法会根据运行环境不同去实例化不同的Environment对象,由于我启动的项目是一个web项目,所以这里会走SERVLET的条件,现在重点就是要看一下在new StandardServletEnvironment()方法中做了哪些事情吧。

	private ConfigurableEnvironment getOrCreateEnvironment() {
		if (this.environment != null) {
			return this.environment;
		}
		switch (this.webApplicationType) {
		case SERVLET:
			return new StandardServletEnvironment();//由于我的项目是一个web服务,所以会创建一个StandardServletEnvironment对象
		case REACTIVE:
			return new StandardReactiveWebEnvironment();
		default:
			return new StandardEnvironment();
		}
	}

 StandardServletEnvironment类继承了StandardEnvironment类,StandardEnvironment类又继承了AbstractEnvironment类。在StandardServletEnvironment,和StandardEnvironment中都没有显示的指定无参构造方法,只有抽象父类AbstractEnvironment中指定了无参构造,我们来看一下其无参构造做了哪些事情:

public AbstractEnvironment() {
		customizePropertySources(this.propertySources);
	}

通过上面的代码看出,构造方法中就一行代码,作用是自定义属性来源,有意思的是在customizePropertySources内部并没有做任何事情,而是有子类去重写这个方法,看到这里让我想到这里还采用了模板方法的设计模式,将特定的动作由子类去实现。那现在我们在来看一下子类是如何定义这个行为的。下面是StandardServletEnvironment类中的方法,看到这我的内心是拒绝的,这个方法又调用了父类的方法(城里人真会玩)。没得办法,那我们来看看父类在这个方法里又干了什么事情吧

protected void customizePropertySources(MutablePropertySources propertySources) {
		propertySources.addLast(new StubPropertySource(SERVLET_CONFIG_PROPERTY_SOURCE_NAME));
		propertySources.addLast(new StubPropertySource(SERVLET_CONTEXT_PROPERTY_SOURCE_NAME));
		if (JndiLocatorDelegate.isDefaultJndiEnvironmentAvailable()) {
			propertySources.addLast(new JndiPropertySource(JNDI_PROPERTY_SOURCE_NAME));
		}
		super.customizePropertySources(propertySources);
	}

 看到这里,我不经心中一喜,getSystemEnvironment不就是从系统环境中获取属性信息吗,看来关键点就在这里了。

protected void customizePropertySources(MutablePropertySources propertySources) {
		propertySources.addLast(
				new PropertiesPropertySource(SYSTEM_PROPERTIES_PROPERTY_SOURCE_NAME, getSystemProperties()));
		propertySources.addLast(
				new SystemEnvironmentPropertySource(SYSTEM_ENVIRONMENT_PROPERTY_SOURCE_NAME, getSystemEnvironment()));
	}
public Map<String, Object> getSystemEnvironment() {
		if (suppressGetenvAccess()) {
			return Collections.emptyMap();
		}
		try {
			return (Map) System.getenv();//jdk包下的方法
		}
}

 为了验证我的猜想,自己写一个简单的测试类看一下,是不是如我们猜想一样:

首先配置jvm运行属性-Dkey=value 接着我们运行这段代码:

public static void main(String[] args) {

        Properties properties = System.getProperties();
        System.out.println(properties.getProperty("key")); //value
  }

运行结果确实是value,看来我们的猜想是对的。

小结:

通过java -java -Dkey=value的方式对springboot中的属性赋值其实并不是spring的独创,spring只是通过System.getenv()拿到系统的环境变量而已


总结

以上就是我关于springboot修改配置文件的一些看法,欢迎大家提出疑问与见解。

Logo

为开发者提供学习成长、分享交流、生态实践、资源工具等服务,帮助开发者快速成长。

更多推荐