I am not sure if this is a valid question, but I was wondering if this was possible.
A Spring boot project has an application.properties and several profile specific properties. The profile specific properties overrides the defined application.properties with whatever has been defined in the application-profile.properties, and also adds those properties belonging exclusively in the profile specific properties. Illustration below:
application.properties
key1=value1
key2=value2
application-profile.properties
key1=valueProfile1
key3=valueProfile3
When the application starts with this profile, the final properties that it sees are as follows:
key1=valueProfile1
key2=value2
key3=valueProfile3
In short, you have a union of both the common and profile properties, with the profile property values appending and overriding the common.
But what if, in a god-knows-what scenario, i need a property to be defined in the common application.properties but i need it to be "undefined" when the application starts in one particular profile. Illustration below:
application.properties
keySpecial=specialValue
key1=value1
key2=value2
application-special.properties
key1=valueSpecial1
//unset or undefine keySpecial
keyAlternateSpecial=specialAlternateValue
key3=valueSpecial3
Now, when the application starts with this "special" profile, I want it to see the final properties as follows:
keyAlternateSpecial=specialAlternateValue
key1=valueSpecial1
key2=value2
key3=valueSpecial3
Note that keySpecial is not defined, doesnt even exist, when the application runs in this special profile.
Is this possible?
Note: I know that I can refrain from defining "keySpecial" in the common application.properties, and define them in all other profile specific properties. And specify "keyAlternateSpecial" only in "special" profile properties.
More Info:
The scenario that made me wonder about this is the spring boot datasource jndi property. From the docs
spring.datasource.jndi-name= # JNDI location of the datasource. Class, url, username & password are ignored when set.
The mere existence of this property makes the application ignore the other datasource properties (class,url,username,password) even if they are set.
I am not allowed to remove the jndi property from the "application.properties". But instead I wanted to unset/undefine it and add the other datasource properties (class,url,username,password) in a "special" profile properties.
You can fake removing spring.datasource.jndi-name from application.property by setting spring.datasource.jndi-name=false. This way #ConditionalOnProperty(prefix = "spring.datasource", name = "jndi-name") won't enable autoconfiguration class. For details look at ConditionalOnProperty javadoc.
I solved in my use case with by defining the JNDI property in default profile which is activated when no other profiles are defined, in this way during development I can use a different datasources without JNDI.
Here's an excerpt of my application.yml file, don't know if this works for you.
spring:
jpa:
database: POSTGRESQL
hibernate:
ddl-auto: none
# Default profile, active by default on JBoss since no spring profiles are activated
---
spring:
profiles: default
datasource:
jndi-name: java:jboss/datasources/anagraficaDS
# Development configuration
---
spring:
profiles: development
datasource:
platform: postgres
url: jdbc:postgresql://localhost:5432/my-db
username: root
password: secret
driverClassName: org.postgresql.Driver
Late to the party, but:
Since SpringBoot 2.4 a good option would be profile groups.
Put keySpecial=specialValue (and other related config) in its own profile - let's call it special.
Then add it to the profiles it needs to be in. So if you have profiles a, b, and c, and you only need special to be in a and b, then:
spring.profiles.group.profilea[0]=special
spring.profiles.group.profileb[0]=special
Related
I have a property with an array value that I want to override when a certain profile is active. But instead of replacing the property Spring Boot performs a strange merge of two arrays. It worked fine on Spring Boot version 1.5 but stopped after upgrading to version 2.5.
I have an application.yml that looks like this:
spring.config.use-legacy-processing: true
configuration:
type:
my-type:
... # some configuration properties
my-list: ['first','second','third']
---
spring:
profiles: dev
configuration:
type:
my-type:
... # some configuration properties
my-list: ['fourth']
I am retrieving this configuration as Map and for property my-list when running with dev profile I am getting an array ['fourth','second','third']. It is the default array with the first element replaced by the value from the profile configuration. If I would replace profile array with ['fourth','fifth'] then the result would be ['fourth','fifth','third'].
I tried to disable legacy processing and use spring.active.on-profile it still works the same way.
If I am consuming properties to class instead of Map then everything works fine but the list of properties is not fixed.
Maybe someone knows what could be done about this?
I'm new to spring and I'm studying it. And stumbled upon the #Profile annotation.
I want to write a simple project with Spring (not Springboot) to learn how to load properties based on the environment using #profile annotation. Almost everywhere, the examples (Ex1, Ex2) I see only with the Springboot. I'm wondering whether we cannot write a Spring application that can dynamically load the properties based on the environment (dev, prod).
Some examples ( Ex3, Ex4, Ex5) show with the #Profile but those have hardcoded the bean details for each environment like below. Is this how we have to write the property loading?
#Profile("dev")
#Bean
public String devDBCcnnection() {
System.out.println(dbConfiguration.getUrl());
return "DB Connection for Dev";
}
#Profile("test")
#Bean
public String devTestCcnnection() {
System.out.println(dbConfiguration.getDriverClassName());
return "DB Connection for Test";
}
#Profile("prod")
#Bean
public String devProdCcnnection() {
System.out.println("DB Connection for Prod");
return "DB Connection for Prod";
}
It has to write a bean for each profile like in the above example?
Can someone tell me using #Profiles, can't dynamically load the property values like in Spring applications?
Appreciate it if you can give the samples with Spring 5
Almost everywhere, the examples (Ex1, Ex2) I see only with the
Springboot. I'm wondering whether we cannot write a Spring application
that can dynamically load the properties based on the environment
(dev, prod).
Spring boot uses the spring context. The spring context allows you to use profiles. Therefore no problem using profiles with simple Spring project (non spring-boot).
There are many ways that you can use Profiles.
One of them is the example that you gave with specific beans that have #Profile and get registered in spring for a specific profile.
Another one, more commonly used in enteprise applications is to ship a jar application with multiple application.yaml files. So for example you ship your application, containing dev-application.yaml and qa-application.yaml. You can then start your application selecting a specific profile to be active. Then that specific application.yaml will be used when the application starts up to build the spring context. So the aplication will be started with qa-application.yaml and will have a connection to the QA database.
But be careful the default application.yaml will also be loaded. The specific application.yaml for example qa-application.yaml will be loaded on top of default application.yaml.
The following article contains very good information about spring profiles
spring profiles article
Considering my example here, I quotte something relevant from that article.
The Default Profile The default profile is always active. Spring Boot
loads all properties in application.yml into the default profile. We
could rename the configuration file to application-default.yml and it
would work the same.
Other profiles will always be evaluated on top of the default profile.
This means that if a property is defined in the default profile, but
not in the qa profile, the property value will be populated from the
default profile. This is very handy for defining default values that
are valid across all profiles.
In order to activate a specific profile
For non spring-boot projects here is a very good answer spring active profile
For spring-boot projects you can
Use a system variable to start your jar file
java -Dspring.profiles.active=qa -jar myApp.jar
Use an environment property to start your jar file
export SPRING_PROFILES_ACTIVE=qa
java -jar myApp.jar
Is there any way to load the respective hibernate config based on the property configured in a properties file.
I have an application to connect to Any database with the same schema through hibernate configs. Right now, I have created two hibernate configs One for DynamoDB another for all hibernate supported SQL's
I wanted to load only respective config by ignoring other config's.
i think we can specify like below
#Profile("prod")
#Configuration
Is it possible to create another property like profile.
There can be multiple profiles active at the same time in your application.
So you can have profiles for specific databases along with the profiles responsible for environment type.
Then, you can define your properties in files called application-dynamodb.properties and application-other.properties
Yes you can use #profile concept here.You can maintain multiple properties file with different configuration and activate that specific configurations for example by adding
spring.profiles.active=dev in application.properties, if application-dev.properties contains the required db configurations.But then you need to add #profile("dev") in configuration class while you are initializing/creating DB connection working with profile
I want to add a custom property to the application.yml of my Cloud Config. The comments in the file say it is for all shared configuration. However, when I do so, it causes the binding of the properties to JHipsters own ApplicationProperties to fail at the class does not have the correct writable property.
application.yml
application:
clients:
- Foo
Stacktrace:
Caused by: org.springframework.boot.bind.RelaxedBindingNotWritablePropertyException: Failed to bind 'application.clients[0]' from 'file:central-config/localhost-config/application.yml' to 'clients[0]' property on 'io.github.jhipster.registry.config.ApplicationProperties'
From JHipster's documentation:
Application-specific properties Your generated application can also
have its own Spring Boot properties. This is highly recommended, as it
allows type-safe configuration of the application, as well as
auto-completion and documentation within an IDE.
JHipster has generated a ApplicationProperties class in the config
package, which is already preconfigured, and it is already documented
at the bottom the application.yml, application-dev.yml and
application-prod.yml files. All you need to do is code your own
specific properties. (emphasis mine)
Have you done that step and added your own properties to ApplicationProperties.java? It looks like you should have a property of type List<String> clients. If you haven't that's why it's failing, because it's attempting to bind a configuration property to the ApplicationProperties class, but the class doesn't contain a property to store it.
Custom Spring boot properties should always be defined in a #ConfigurationProperties class within the app so that their value can be setup in the yml file. This is thoroughly documented in the spring boot documentation:
https://docs.spring.io/spring-boot/docs/current/reference/html/boot-features-external-config.html
Is it possible to have a profile in spring boot and also another profile that inherits most of the parent values and beans?
For example I have two profiles
staging and staging-task.
I want staging-task to inherit the database configuration of the staging profile however I want it to override the jpa configuration.
Is profile inheritance available to #Configuration beans.
Yes. Its possible to have spring profiles in spring boot.
For your problem, put your common database configuration in application.yml(default profile).
And you can override the other properties in application-stage.yml.
Spring will read the properties from application.yml and override from application-stage.yml when active profile is stage.
TL;DR
The active profiles will cause respective application-$profile.properties to be read (if they exist) in the order the active profiles are defined. Later read properties override earlier ones. That will give you the means to do smth. like an hierarchy.
Long Version
There is no such thing as profile-inheritance in spring but it can be mimicked as written in the answer by JRR.
For how it actually works read: https://docs.spring.io/spring-boot/docs/current/reference/html/boot-features-external-config.html#boot-features-external-config-profile-specific-properties.