spring yml file for specific environment - java

I have 3 yml files namely
application-default.yml -> default properties, should be available
in all profiles
application-dev.yml -> properties only for dev
profile
application-prod.yml -> properties only for prod profile
When I start my boot application by passing the -Dspring.profiles.active=dev,I am able to access the application-dev.yml specific properties.
But I cant get the properties defined in the application-default.yml files.
Following is my application-dev.yml file:
Spring:
profiles:
include: default
spring.profiles: dev
prop:
key:value

TL;DR
Just rename the application-default.yml file to application.yml and will work as you expect.
Explanation
According to the description in the docs, a file called application-{suffix}.yml is activated when you run your application with the profile which name matches with the suffix. In addition, the main application.yml is loaded by default so it's the perfect place to put common properties for all profiles. Alternatively, if you want to keep the name of your file as application-default.yml you can pass two profiles to your Spring Boot application:
-Dspring.profiles.active=default,dev
This way you will activate two profiles and both properties files will be loaded.

I was able to solve my problem, here is what I did.
Created a file application-common.yml, put the common properties there.
Then in the application-{env}.yml files I put this on the top.
spring:
profiles:
include: default
Since I dont need to ever load the default profile specifically, this works for me!!!

What I do is:
Put common settings in application.xml, and in this file add:
spring:
profiles:
active: dev, pro, xxx...
all the profiles you want to activate.
So that you just edit this file to switch environment.
Remember that external files procedes, so you can leave another application.xml outside of the WAR to activate dev/pro/... environment instead of editing this file every time. Be sure to check the documentation:
https://docs.spring.io/spring-boot/docs/current/reference/html/boot-features-external-config.html

Related

Spring Boot: Load common config application properties file using bootstrap.yml

In our config server we have following application properties files:
helloApp-dev.properties //dev env properties
helloApp-commonConfig.properties //common properties across env
The properties are accessible from URI like:
https://myapp.abc.com/1234/helloApp-dev.properties
https://myapp.abc.com/1234/helloApp-commonConfig.properties
Below is our bootstrap.yml of helloApp application:
---
spring:
application:
name: helloApp
---
spring
profiles: dev
cloud:
config:
label: 1234
name: {spring.application.name}
uri: https://myapp.abc.com/
I am using Spring boot version 2.2.4. The helloApp-dev.properties are loading successfully in application but not commonConfig.
The configuration in commonConfig is not being loaded because you are not indicating to Spring that it should load that profile/config, because you are activating only the dev profile - and the configuration for that profile is the one which is being loaded:
---
spring
profiles: dev
In addition to the good solutions proposed by #akozintsov in his/her answer, if you need to include certain common configuration in different environments or profiles, let's say dev, qa or prod, you can use the spring.profiles.include configuration property and include, as a comma separated list of values, if using properties files, or as a list, if using yaml, the different common profiles and corresponding configurations you need to.
In your example, in helloApp-dev.properties you need to include the following information within the rest of your configuration:
spring.profiles.include=commonConfig
These related SO question and this article could be of help as well.
To load properties file, profiles should match.
You have 2 solutions:
Rename helloApp-commonConfig.properties -> helloApp.properties
Use multiple profiles for your application (dev, commonConfig)

Disable spring-context-indexer by profile

I want to enable Spring Context Indexer on a project but I am having issues with Swagger3 (check here and here).
I understand the limitations and would like to enable it, at least, at the DEV profile where we do not need Swagger running.
My goal is to disable indexing on PROD environment. From docs:
you can fallback to a regular classpath arrangement (as though no index was present at all) by setting spring.index.ignore to true, either as a system property or in a spring.properties file at the root of the classpath.
My first approach (without success) was setting an env var (Windows 10) with the following:
SPRING_APPLICATION_JSON={"spring":{"index":{"ignore":true}}}
If I create a spring.properties file and set the value accordingly it works. But I can't figure how to use different properties for each profile, I imagined it was something like the application.properties file but I was wrong.
How can I achieve that?
EDIT:
Just to be clear, this config (spring.index.ignore) will just work if inside a spring.properties file, not an application.properties one. (Just double-checked before this edit)
Actually I have one application-prod.properties and one application-dev.properties.
I don't know the difference between spring.properties and application.properties but the first one doesn't seem to work with multiple profiles as the later.
Edit 2:
Just went through org.springframework.context.index.CandidateComponentsIndexLoader and it uses SpringProperties.getFlag(IGNORE_INDEX) to read the value.
SpringProperties class is clear about the file it uses:
Reads a spring.properties file from the root of the Spring library classpath, and also allows for programmatically setting properties through setProperty. When checking a property, local entries are being checked first, then falling back to JVM-level system properties through a System.getProperty check.
I think I will need to pass a property to Java runner during initialization. Will research a little bit more about it.
you can use different application.properties file as follow:
add the following files to the resource folder:
application.properties
spring.profiles.active=dev #place profile name you want to use
application-dev.properties
#dev properties
...
You can create many application-env.properties you may wish
application-env.properties
#env properties
...
Spring Boot supports profile-specific properties files. You have to name these files with the following format: application-{profile}.properties. You can activate a profile via JVM system parameter: -Dspring.profiles.active=dev. You can read more about this subject here: https://www.baeldung.com/spring-profiles

How to resolve placeholder in properties file with values from another properties file in spring boot application

My spring boot application has below properties files.
src/main/resources/config/DEV/env.properties
mail.server=dev.mail.domain
src/main/resources/config/QA/env.properties
mail.server=qa.mail.domain
src/main/resources/config/common/env.properties
mail.url=${mail.server}/endpoint
Is it possible to load "common/env.properties" so that it's placeholders will be resolved using the given environment specific properties file. For DEV environment, we want the placeholders in "common/env.properties" to be resolved using values from "DEV/env.properties".
There are answers about how to load multiple properties files and profile based loading but could not find an answer for this particular use case.
Thanks in advance.
2 Options :
Generate the common/application.properties using configuration-maven-plugin and filter files for each environment. It is outdated now.
Use application-<env>.properties for each environment and pass the -Dspring.profiles.active=<env> as VM option in application start up. Spring will automatically take the property from correct file.
In option 2, you will be overwriting whatever is present in application.properties with application-.properties. So you dont have to add only the properties which you need to change per environment.
for eg:
Your application.properties can have
logging.level.root=WARN
logging.level.org.apache=WARN
logging.level.org.springframework=WARN
Your application-dev.properties can have
logging.level.org.springframework=DEBUG
which means, when you are starting application using dev profile, spring takes
logging.level.root=WARN
logging.level.org.apache=WARN
logging.level.org.springframework=DEBUG
edit :
Also, you can try something like below on your class. (Spring will overwrite value in config.properties with values from config-dev.properties). ignoreResourceNotFound will make sure, application will still start with default values even if the corresponding file is not found.
#Configuration
#PropertySource("classpath:config.properties")
#PropertySource(value = "classpath:config-${spring.profiles.active}.properties", ignoreResourceNotFound = true)
You can add resources/application.yml file where you can have multiple profiles in one File.
MultiProfile Yaml
e.g.here are two different profiles 'dev' and 'qa' with different applicationNames 'DEV' and 'QA' and one defaultName 'Default'
spring:
application:
name: Default
profiles:
active: qa
---
spring:
profiles: dev
application:
name: DEV
---
spring:
profiles: qa
application:
name: QA
You can achieve this by declaring a property source on a class configuration and setting up an environment variable in the path :
#PropertySource({ "classpath:config/${env}/env.properties" })
#Configuration
public class config{}
And then you launch the spring boot app with the command line variable -env=dev
UPDATE
You can use #PropertySources annotation to load several properties.
#PropertySources({
#PropertySource("classpath:config/${env}/env.properties"),
#PropertySource("classpath:config/common/env.properties")
})
public class config{}

How do I get multiple default values in properties across different profiles?

I have a few microservices with the same configuration, with each depending on a Spring profile. #ConfigurationProperties takes the values that I have in my YAML application profile file. I want to move this configuration to a common project and out of the microservices YAML configuration.
The problem is that I have 2 different configurations for different profiles. I can use #Value to inject default values, but I can do that only once. Is there a way to have multiple default values contingent on a specific Spring profile?
In my project we use Java configuration, not XML.
Do you mean like below ? I have two profiles A1 & B1 with the same property (app.port) in the same yml file (application.yml). The profiles are separated by ---
---
spring:
profiles: A1
app.port: 8080
---
spring:
profiles: B1
app.port: 9090
---
If you want to read properties from common location then write bootstrap.yml in your microservices and delete application.yml.
bootstrap.yml:
spring:
config:
location: file:/home/external/properties/location/
name: application
profiles:
active: dev
file location: /home/external/properties/location/
suppose you need dev and prod environment.Then keep this 3 properties file in this location.
application.yml
application-dev.yml
application-prod.yml
Spring boot read application.yml properties first. If set active profile dev in bootstrap.yml then application.yml value overwirte by application-dev.yml.
For different value just change active profile in bootstrap.yml of your microservices.
According to my search, I cannot resolve this issue as I want. Probably spring-cloud-config would resolve my problem but I don't want to implement this one. I changed the library and don't need to have these separate configs anymore.

Spring properties file set null to property

Currently I have a few property files in my src/main/resources folder:
- application.properties
- application-dev.properties
- application-test.properties
Now, when I specify a profile, it loads both that profile's specific file and the general application.properties, overwriting everything with the former.
However, when my application is deployed in production, no profile is passed, so application.properties must be my production file.
That's fine because I can overwrite everything in the profile specific ones. There is one problem, however; on production, I now need to set:
spring.datasource.jndi-name=jdbc/appname
When I add that to application.properties, every profile also inherits that, and then, when I run dev server or a test, it gives me this error:
Caused by: javax.naming.NoInitialContextException: Need to specify class name in environment or system property, or as an applet parameter, or in an application resource file: java.naming.factory.initial
Because I indeed don't use this JNDI stuff on my own environments; I use the following properties:
spring.datasource.url=jdbc:url
spring.datasource.username=user
spring.datasource.password=pass
My problem is: I cannot overwrite this property for my life. If I add any of these on the env specific files, it will be ignored and the error persists:
spring.datasource.jndi-name= # empty string, does nothing
spring.datasource.jndi-name=<null> # read somewhere it meant null, doesn't work
spring.datasource.jndi-name=${inexistentProp} # I though it might return null, but gives an error
So, what can I do? I think of several solutions:
A way to set a property value as proper null or undefined in a spring property file (since empty doesn't do the trick)
A way to change the commonly inherited property file to something else (I tried #PropertySource, but it only add more options, always falling back to application.properties eventually)
Disable JNDI altogether via properties file, despite the former property (I tried spring.jndi.ignore=true as per here, but to no avail)
But either I don't know how or they don't work.
Spring Boot documentation, 24.4 Profile-specific Properties:
In addition to application.properties files, profile-specific properties can also be defined by using the following naming convention: application-{profile}.properties. The Environment has a set of default profiles (by default, [default]) that are used if no active profiles are set. In other words, if no profiles are explicitly activated, then properties from application-default.properties are loaded.
25.1 Adding Active Profiles:
The spring.profiles.include property can be used to unconditionally add active profiles.
So, create a application-default.properties file with the following property:
spring.profiles.include=prod
Now move the spring.datasource.jndi-name=jdbc/appname property from the application.properties file to the application-prod.properties file.
When you run code with a specific profile, the prod profile will not be used, and spring.datasource.jndi-name will be undefined.
When you run code in production, where no profile is specified, the prod profile is included by default, and spring.datasource.jndi-name will be defined.
You can of course just put the production properties in the application-default.properties itself, but the above approach makes it more clear what you're doing.
It also makes it easier if you end up with multiple profiles. E.g. you have prod vs dev vs test. But what if you have independent set of profiles such as foo vs bar, and that default production environment should be prod,foo? Allowing alternate production environment to use prod,bar, and each can be tested separately (test,foo and test,bar).
By using the default profile to only include other profiles, without otherwise define any properties, you can now manually mix and match profiles, as needed.

Categories