ChatGPT解决这个技术问题 Extra ChatGPT

How to override application.properties during production in Spring-Boot?

I'm using spring boot and application.properties to select a database during development by @Configuration @Profile("dev").

spring.profiles.active=dev
spring.config.location=file:d:/application.properties

During production I'd like to create a file outside of the application context that should be loaded and then active a different configuration profile, with d:/application.properties:

spring.profiles.active=production

Result: when I start the app, the configuration is still dev, so somehow the additional location of the productive properties file is not taken into account. Am I missing anything?

spring boot 1.1.0.BUILD-SNAPSHOT

Note: this question is NOT about tomcat.

I would do it the other way around, configure for production and override for dev/test. If I'm not mistaken the spring.config.location can only be set from the command-line and not from within a properties file.
spring.config.location can be configured from any of the supported property sources, not just command line
Does Spring still support the ProertyPlacholder mechanism? If so you might want to look into that.
The configuration you have posted works, there is nothing wrong with Spring Boot. You must have something else that's not working or you might have overlooked something in your project. How do you check a certain profile is loaded and not the other?
Do you have other application.properties files located in other directories of your project?

x
xlm

I know you asked how to do this, but the answer is you should not do this.

Instead, have a application.properties, application-default.properties application-dev.properties etc., and switch profiles via args to the JVM: e.g. -Dspring.profiles.active=dev

You can also override some things at test time using @TestPropertySource

Ideally everything should be in source control so that there are no surprises e.g. How do you know what properties are sitting there in your server location, and which ones are missing? What happens if developers introduce new things?

Spring Boot is already giving you enough ways to do this right.

https://docs.spring.io/spring-boot/docs/current/reference/html/boot-features-external-config.html


While this question was from my early days with spring-boot, I now agree that a profile should only be activated by command line parameter spring.profiles.active=production when running the jar/war. So i'm going to accept your answer.
Would application.properties run if profile is set to production?
yes, it would do application and application-production, if properties are same, later would work as override
While grouping sets of configuration values using spring profiles may be common practice in Spring/Java it's important to point out that this isn't considered best practice for modern services and applications especially those who aim to follow cloud native practices such as that described in 12factor.net/config.
They say use env vars, which is a joke. In my app I have config server, that has yml files, and hashicorp vault. The app lives in pcf. The config is checked in to git independent of the code, which is good enough. Yml allows import of other ymls
B
Ben W

You can also use @PropertySources

@PropertySources({
        @PropertySource(value = "classpath:application.properties"),
        @PropertySource(value = "file:/user/home/external.properties", ignoreResourceNotFound = true)
})
public class Application {
    public static void main(String[] args) throws Exception {
        ConfigurableApplicationContext context = SpringApplication.run(Application.class, args);

    }


}

Works for me with two remarks: 1. definitions in the second resource override those in the first one. 2. unless the first resource is named application.properties (at least in Spring ver. 4.3.20) It seems Spring 4 has a bug that prevents overriding. Just rename application.properties -> app.properties and all would be fine.
G
Gabriel Ruiu

I am not sure you can dynamically change profiles.

Why not just have an internal properties file with the spring.config.location property set to your desired outside location, and the properties file at that location (outside the jar) have the spring.profiles.active property set?

Better yet, have an internal properties file, specific to dev profile (has spring.profiles.active=dev) and leave it like that, and when you want to deploy in production, specify a new location for your properties file, which has spring.profiles.active=prod:

java -jar myjar.jar --spring.config.location=D:\wherever\application.properties

That's the way I intended: having an internal application.properties file defining spring.config.location and spring.profiles.active=dev and override external. But does not work...
Dont define spring.config.location in your internal file, just specify it as a commandline argument when you want to deploy into production
Yes that would be an option, but I'd like to prevent having to give any cmd args when starting. Especially as spring boot claims to support this...
It may just be some quirk in my set up, but the "--spring.config.location=..." does not work for me. I HAVE to use "-Dspring.config.location=..." That is "-D" not "--".
@StephenGelman Don't forget to pass args to SpringApplication. Like public static void main(final String[] args) { SpringApplication.run(Application.class, args);}
K
Koray Tugay

From Spring Boot 2, you will have to use

--spring.config.additional-location=production.properties

S
Surasin Tancharoen

Update with Spring Boot 2.2.2.Release.

Full example here, https://www.surasint.com/spring-boot-override-property-example/

Assume that, in your jar file, you have the application.properties which have these two line:

server.servlet.context-path=/test
server.port=8081

Then, in production, you want to override the server.port=8888 but you don't want to override the other properties.

First you create another file, ex override.properties and have online this line:

server.port=8888

Then you can start the jar like this

java -jar spring-boot-1.0-SNAPSHOT.jar --spring.config.location=classpath:application.properties,/opt/somewhere/override.properties

This does not work anymore. You should use --spring.config.additional-location to override the default properties
If you want to override with --spring.config.location=classpath:application.properties,/opt/somewhere/override.properties you have to override all the properties in the new file present in the default file
@homeOfTheWizard which version are you using ?
I am using 2.2.6.Release
Thanks a lot. It works with Spring Boot 2.3.4 (properties or yml files)
C
Community

UPDATE: this is a bug in spring see here

the application properties outside of your jar must be in one of the following places, then everything should work.

21.2 Application property files
SpringApplication will load properties from application.properties files in the following    locations and add them to the Spring Environment:

A /config subdir of the current directory.
The current directory
A classpath /config package
The classpath root

so e.g. this should work, when you dont want to specify cmd line args and you dont use spring.config.location in your base app.props:

d:\yourExecutable.jar
d:\application.properties

or

d:\yourExecutable.jar
d:\config\application.properties

see spring external config doc

Update: you may use \@Configuration together with \@PropertySource. according to the doc here you can specify resources anywhere. you should just be careful, when which config is loaded to make sure your production one wins.


OK that might work on an executable jar, which is great! But what about a tomcat web application? How can I load a properties file similar to the config dir outside the deployed war app? Because, when I redeploy the app, any created subfolders will be lost.
with propertysource it should work as long as your spring version good enough for it see update
@dasAnderl The issue with '@PropertySource' for loading properties when deploying a war is that the logging properties will be ignored and the logging system will not work. Check this alternative solution
a
avi.elkharrat

I have found the following has worked for me:

java -jar my-awesome-java-prog.jar --spring.config.location=file:/path-to-config-dir/

with file: added.

LATE EDIT

Of course, this command line is never run as it is in production.

Rather I have

[possibly several layers of] shell scripts in source control with place holders for all parts of the command that could change (name of the jar, path to config...)

ansible deployment scripts that will deploy the shell scripts and replace the place holders by the actual value.


This could be because the answer was posted in a previous version of SB
H
Himadri Mandal

The spring configuration precedence is as follows.

ServletConfig init Parameter ServletContext init parameter JNDI attributes System.getProperties()

So your configuration will be overridden at the command-line if you wish to do that. But the recommendation is to avoid overriding, though you can use multiple profiles.