72

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.

membersound
  • 81,582
  • 193
  • 585
  • 1,120
  • 4
    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. – M. Deinum May 09 '14 at 11:31
  • 4
    spring.config.location can be configured from any of the supported property sources, not just command line – Gabriel Ruiu May 09 '14 at 11:36
  • 1
    Does Spring still support the ProertyPlacholder mechanism? If so you might want to look into that. – Mikkel Løkke May 09 '14 at 11:41
  • 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? – Andrei Stefan May 09 '14 at 12:09
  • Do you have other `application.properties` files located in other directories of your project? – Andrei Stefan May 09 '14 at 12:12
  • I have one at `src/main/resources/application.properties` and `D:/application.properties`. I have two `@Configuration @Profile("dev/prod")` classes, one going to an embedded h2, one to postgres. So on startup I directly see which profile is chosen, and it's always the one of the classpath properties file, never the local file outside the classpath. – membersound May 09 '14 at 12:54
  • Do you have anything else in the two application.properties files other than what you posted already? – Andrei Stefan May 09 '14 at 13:04
  • No just what I posted. I also created a testproject now that has plain simple classes to reproduce my problem: https://drive.google.com/file/d/0B0qVi9D7R5MZM3ZSNFRlQnJlZmc/edit?usp=sharing – membersound May 09 '14 at 13:23
  • Possible duplicate of [How to externalize Spring Boot application.properties to tomcat/lib folder](http://stackoverflow.com/questions/31017064/how-to-externalize-spring-boot-application-properties-to-tomcat-lib-folder) – amdev Dec 08 '16 at 12:07

8 Answers8

48

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

xlm
  • 6,854
  • 14
  • 53
  • 55
Kalpesh Soni
  • 6,879
  • 2
  • 56
  • 59
  • 6
    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. – membersound Mar 29 '18 at 08:11
  • 3
    Would `application.properties` run if profile is set to `production`? – Lokesh Oct 24 '18 at 07:22
  • 10
    yes, it would do application and application-production, if properties are same, later would work as override – Kalpesh Soni Oct 25 '18 at 19:28
  • 2
    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 https://12factor.net/config. – jpierson Sep 30 '20 at 03:35
  • 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 – Kalpesh Soni Sep 30 '20 at 15:02
25

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);

    }


}
Ben W
  • 2,469
  • 1
  • 24
  • 24
  • 2
    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. – Alexander Vasiljev Aug 03 '20 at 08:52
  • Same as @AlexanderVasiljev – Denis Abakumov May 10 '23 at 18:40
17

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
Gabriel Ruiu
  • 2,753
  • 2
  • 19
  • 23
  • 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... – membersound May 09 '14 at 11:53
  • Dont define spring.config.location in your internal file, just specify it as a commandline argument when you want to deploy into production – Gabriel Ruiu May 09 '14 at 11:55
  • 3
    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... – membersound May 09 '14 at 12:06
  • 1
    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 "--". – Steve Gelman Dec 11 '14 at 00:13
  • @StephenGelman Don't forget to pass args to SpringApplication. Like `public static void main(final String[] args) { SpringApplication.run(Application.class, args);}` – Tuno Oct 30 '15 at 07:14
  • Best answer! Worked great on 1.5.9.RELEASE + java 8 on mac os. – user674669 Apr 05 '18 at 20:25
  • Shouldn't it be --Dspring.config.location=... – SJuan76 Jul 04 '22 at 13:30
  • @SJuan76 it's '-D' because thats how you can specify JVM arguments – Gabriel Ruiu Jul 05 '22 at 11:29
13

From Spring Boot 2, you will have to use

--spring.config.additional-location=production.properties
Koray Tugay
  • 22,894
  • 45
  • 188
  • 319
Selvakumar Ponnusamy
  • 5,363
  • 7
  • 40
  • 78
7

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
Surasin Tancharoen
  • 5,520
  • 4
  • 32
  • 40
5

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.

Community
  • 1
  • 1
  • 1
    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. – membersound Sep 15 '14 at 15:15
  • 1
    with propertysource it should work as long as your spring version good enough for it see update – dasAnderl ausMinga Sep 15 '14 at 22:11
  • @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](http://stackoverflow.com/questions/31017064/how-to-externalize-spring-boot-application-properties-to-tomcat-lib-folder/31027378#31027378) – Daniel Mora Jun 26 '15 at 11:28
5

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.
avi.elkharrat
  • 6,100
  • 6
  • 41
  • 47
1

The spring configuration precedence is as follows.

  1. ServletConfig init Parameter
  2. ServletContext init parameter
  3. JNDI attributes
  4. 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.

Himadri Mandal
  • 325
  • 2
  • 11