Spring boot : load profile specific application.properties from file system - spring

I am trying to load external properties files based on the current active profile
and the properties files I have defined as below :
default -> resources/config/application.properties (for dev)
qa -> c:\external-configuration\config\application-qa.properties
prod -> c:\external-configuration\config\application-prod.properties
how spring can be configured to read all these application*.properties from different sources?
I tried to define a PropertySourcesPlaceholderConfigurer as below but spring could resolve the properties value based on the active profile, I always get the default values defined in application.properties
#Bean
public PropertySourcesPlaceholderConfigurer propertySourcesPlaceholderConfigurer() {
PropertySourcesPlaceholderConfigurer properties = new PropertySourcesPlaceholderConfigurer();
properties.setLocation(new FileSystemResource("c:\external-configuration\config\application-qa.properties"),new FileSystemResource("c:\external-configuration\config\application-prod.properties"));
properties.setIgnoreResourceNotFound(false);
return properties;
}

First specify which profile you want to load with spring.profiles.active. Secondly, as it isn't one of the default locations, add spring.config.additional-location to add additional locations to scan. So when you start your line should look like
java -jar <your-jar>.jar --spring.profiles.active=prod --spring.config.additional-location=file:C:/external-configuration/config/
This is also documented in the Spring Boot documentation.
And remove your custom PropertySourcesPlaceholderConfigurer as that isn't needed.

You can also use java annotation for property resource and use server environment (active profile) to identify which properties file to load.
Like, this code snippet here, it will look for property 'envTarget' and in case its not found or null, it will use default 'qa':
#PropertySource({
"classpath:application-${envTarget:qa}.properties"
})

Related

Spring Boot application to have separated multiple property files

Coming from Play Framework, a handy feature that has helped to organize the application configurations was to use includes (Link) to spilt the various configurations into multiple .conf files as below.
application.conf Content
include "play-http.conf"
include "play-modules.conf"
include "play-i18n.conf"
include "authentication.conf"
include "hbase.conf"
include "custom-caches.conf"
include "custom-filters.conf"
#Any other root level application configurations
Is there an equivalent to this in Spring Boot .properties files?
From Spring 2.4, we can create multiple properties file for each profiles as below.
application-main1.properties
application-sub1.properties
application-sub2.properties
And then in default application.properties file we can group all sub profiles and activate the main profile
spring.profiles.group.main1=sub1,sub2
spring.profiles.active=main1
I am not sure if we can group sub profiles under default profile. You can try out
spring.profiles.group.default=sub1,sub2
This way you don't need to have another file for main profile.
I use yaml configuration files myself but I think that the configuration is mostly similar. You should take a look at the PropertySourcesPlaceholderConfigurer.
I have defined a PropertySourcesPlaceholderConfigurer bean to use a configuration override file located outside of the jar. Anything that is in the override file will be used instead of the default configuration. Anything that is not in the override file is still retrieved from the default configuration file. I think you can create a similar bean to achieve what you are looking for.
Here's my code:
#Bean
static PropertySourcesPlaceholderConfigurer propertySourcesPlaceholderConfigurer() {
var properties = new PropertySourcesPlaceholderConfigurer();
properties.setLocation(new FileSystemResource("./application.yaml"));
properties.setIgnoreResourceNotFound(true);
return properties;
}
For my use case, I only needed to define one properties location, but it is also possible to specify multiple locations:
...
properties.setLocations(Resource... locations);
...
My requirement was simply achieved using the spring.config.import (Link).
I created multiple property files such as hbase.properties, custom-caches.properties etc. And then in my application.properties imported those additional property files as below.
spring.config.import=hbase.properties,custom-caches.properties
#Any other properties in the application.properties file
Thanks

Restricting #PropertySource to specific #Configuration classes in spring

I have the following property files:
application.properties - Base spring config
common.properties - Common config
servicea.properties - Service specific config
password.properties - Password Config
Based on the last three files, I have 3 <Name>Property classes in the following format.
#Configuration
#PropertySource("file:<filepath>")
public class ServiceAProperties {
private final Environment env;
#Autowired
public ServiceAProperties (Environment env) {
this.env = env;
}
public String getTest() {
String test = env.getProperty("application.test"); // Accessible - Not Intended
test = env.getProperty("common.test"); // Accessible - Not Intended
test = env.getProperty("servicea.test"); // Accessible - Intended
test = env.getProperty("password.test"); // Accessible - Not Intended
return env.getProperty("servicea.test");
}
}
For some reason even though I only have the respective Property classes marked with their specific property file paths, they are also picking up paths from other files and adding it to the env.
How can I make sure that I my environment to be generated only from the files I specify?
The spring docs for #PropertySource says:
Annotation providing a convenient and declarative mechanism for adding
a PropertySource to Spring's Environment. To be used in conjunction
with #Configuration classes.
This means that there is only one Spring Environment. When you have multiple classes annotated with this annotation they will always contribute to the same environment because there is only one.
So, to answer your question, in your case the environment will always be filled with data from all classes that have #Configuration and #PropertySource annotations.
In order to fill the environment with data that you specify, you can use profile specific properties. You can separate the data in multiple profiles and choose the profiles that will be activated (and which data will be accessible in the environment).
I am sharing my own solution to this since I was not able to find an acceptable answer.
Using a new ResourcePropertySource("classpath:<location>") allows you to load in multiple individual property files using their respective individual objects.
Once loaded, the configuration can be accessed in the same way as before propertiesObj.getProperty("propKey")

Spring Reload Properties on Demand

I am looking to load properties from file On Demand in my spring boot application.
I have a requirement to load the properties from the file when there is a change in the properties file.
I am using #Configuration properties to load the properties, by setting the spring.config.location=file:/../test-properties.yml.
Bean class that holds the data
#Configuration
#ConfigurationProperties
public class GetValues {
List<String> values = new ArrayList<String>();
//getters and setters
}
test-properties.yml
values:
- X1
- X2
- X3
I have a rest service to load the data loaded from properties file to backend, within which I am Autowiring the GetValues Bean.
Whenever there is a change in the property file, I will call this service which would load the properties to the Backend.
Right Now, It is loading the same properties everytime, as the properties are already loaded in to the context.
Is there a way to reload the properties from the file everytime I hit the service? I don't want to use the Spring-Cloud, #RefreshScope.
There are two solutions
Using spring devtools you can achieve auto restart when config file change. Only desirable in development environment.
Make that when you hit the service the properties file get loaded, and update your config class attributes. Abstract:
Properties prop = new Properties();
InputStream input = null;
input = Thread.currentThread().getContextClassLoader().getResourceAsStream(fileNameProperties);
prop.load(input);
bean.setValue(prop.getProperty("attribute1"));
If you don't want to use Spring Cloud Config / #RefreshScope, one option would be to the usage of a FileChangeListener / WatchService found in Apache commons (or similar library) or JDK 7 and reload the properties. Make sure you synchronize the usage of the loaded properties and updating them when the file changes, maybe through a ReentrantReadWriteLock.

Spring : How to give properties file to Java.exe

I am using Spring to develop a Java application. I have stored certain properties in a properties file, which is packaged as a JAR. The properties are read in code using #Value annotation. Now when i deploy the JAR i want to supply new values for some of these properties. I know that we can give the new property value as "-Dproperty-name=property-value". But is there a way to give a new property file itself as input which has many properties to be overridden together?
Thanks
Chenbaga
You can have a number of different property files and then load then with a specific system parameter.
#Configuration
#PropertySource(value = {"classpath:/app.properties", "file:/${configLocation}/app.properties"}, ignoreResourceNotFound = true)
public class AppConfig {
Add your default app.properties to /src/resources/app.properties
Then when you start your JVM you can override with
-DconfigLocation=/home/config
If the configLocation is present it will first pick up the default properties, then override then with the ones from the file. If the system parameter is not present it will not file the file and use the defaults.
See http://docs.spring.io/spring/docs/4.3.9.RELEASE/javadoc-api/org/springframework/context/annotation/PropertySource.html for more examples

Set/override Spring / Spring Boot properties at runtime

At the project with Spring Boot we use application.properties but need to configure some of these properties (like port number of logging level) based on an external configuration. We access the configuration via API so it is known only at runtime.
Is there a way to override or set some Spring properties at runtime (for example using a bean) and if yes how can this be achieved?
You could do this with Spring Cloud Config
Just for the purpose of illustration, here's a relatively quick way to see dynamic property overrides at runtime:
First, for your bean to be able to pick up changed properties, you need to annotate it with
#RefreshScope
Add the spring cloud dependency to your spring boot app, eg for gradle
compile group: 'org.springframework.cloud', name: 'spring-cloud-starter', version: '1.1.1.RELEASE'
( NB You also need the spring boot actuator dependency.)
With the app running, you can view your current config at eg
http://localhost:8080/env
eg if you have a property 'my.property' in application.properties, you'll see something like:
"applicationConfig: [classpath:/application.properties]": {
"my.property": "value1",
etc
To change the value, POST my.property=value2 to /env as application/x-www-form-urlencoded
eg
curl -X POST http://localhost:8080 -d my.property=value2
GET /env again and you'll see the new value appears under the "manager" section
To apply the changed properties, do an empty POST to /refresh. Now your bean will have the new value.
Could you use system properties to pass in the variable? If you configure the PropertyPlaceholderConfigurer you can set the precedence of system properties vs file properties.
For example, something like:
#Bean public PropertyPlaceholderConfigurer placeHolderConfigurer() {
PropertyPlaceholderConfigurer props = new PropertyPlaceholderConfigurer()
props.setSystemPropertiesMode( PropertyPlaceholderConfigurer.SYSTEM_PROPERTIES_MODE_OVERRIDE )
props.setLocations(new
PathMatchingResourcePatternResolver().getResources("classpath:/**.properties"));
props
}
The above would load your .properties file, but we set the priority to be system variables first, so if you set a system variable that will override the same variable in the config.
Alternatively, looking at the docs, Spring recommends defining a search order in your Environment:
[PropertyPlaceholderConfigurer is still appropriate for use when]
existing configuration makes use of the "systemPropertiesMode" and/or "systemPropertiesModeName" properties. Users are encouraged to
move away from using these settings, and rather configure property
source search order through the container's Environment; however,
exact preservation of functionality may be maintained by continuing to
use PropertyPlaceholderConfigurer.
Hopefully one of the above should sort out what you need?

Resources