ImportResource conditional choose of spring configuration - java

I have spring application that is configured by Spring annotation and I need to load complex spring xml configuration that is dependent on env system property. is it possible to do it in annotation? I need something like is in #ImportResource (it is only my idea):
#ImportResource("classpath:spring/${env:dev} == dev ? config-dev.xml : config.xml")
#Configuration
public class AppConfig{
}
I can have these env: dev, prod, uat and I need to ensuere that for dev I will load config-dev.xml otherwise I need to load config.xml. Is it possible to do something like this in #ImportResource?

Related

Spring Boot Property file precedence

In my Spring Boot program I'm getting a failure due to a bad property value on load. In particular, it uses the DB2 hibernate dialect but it's not defined in the property file I thought I was using.
Assuming no annotations, where does Spring look for the properties file? Yes I know it normally resides in src/main/resources/application.properties
What if I have a property in my test cases; does it ignore the one in main and use the one in test? Or does it start with the main version and let the test one override the main where it applies?
Does the application profile affect the property file used? Some people use the same application.properties file name in both main and test.
If I do have a TestSource annotation with a class path location, does it still augment it with something somewhere else?
Finally, how can I get Spring to tell me everywhere it looked for properties and not just one of them?
#Woodsman
It's possible to use many settings in each profile/environment in spring application on src/main/resources/ folder
application-dev.properties
application-local.properties
application-onlytests.properties
application-prd.properties
application.properties
the name after hyphen will be the name profile got by spring
Ex: application-{myenviroment}.properties
When you start spring application will be used application.properties by default.
You can tell spring to use an specific properties passing the environment in one of ways below:
Putting spring.profiles.active=prd inside application.properties file
Passing by parameters when start spring app --spring.profiles.active=local
Running your jar on command line java -jar myjar.jar --spring.profiles.active=dev
Setting an environment var in your machine/docker/container SET SPRING_ACTIVES_PROFILE=local
There are other ways using annotations on beans, passing jvm arguments and others
If you need run your tests in a specific configuration ( vars, database, settings ), It's possible to pass which .properties will be used
#ExtendWith(SpringExtension.class)
#AutoConfigureMockMvc
#SpringBootTest
#TestPropertySource(locations = "classpath:application-onlytests.properties")
public class RunTest_from_onlytests_properties {
#Autowired
private MockMvc mockMvc;
#Test // org.junit.jupiter.api.Test
public void test() throws Exception{
// ...
}
}

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{}

Spring Framework PropertySource based on Profile

I have a Spring Boot multi-module maven project. I want my library module to handle its own properties.
So, in the library module:
src/java/resources/module-name/application.properties
src/java/resources/module-name/application-dev.properties
src/java/resources/module-name/application-prod.properties
I have a #Configuration class in that module with:
#PropertySource("classpath://module-name/application-dev.properties")
Obviously, this will only load the dev properties.
2 Questions:
1) How do I factor in #Profile in here so I don't have to create multiple configuration classes, each with its own #Profile. Is there a way to combine the annotations or parameterize them with something like application-${spring.active.profile}.properties?
2) How do I achieve the same behavior vis-a-vis application.properties file as I would have out of the box if these files were in the root of the classpath and picked up automatically by Spring? In other words, I'd like to place all the common properties into application.properties file and only the profile specific ones into application-dev.properties or application-prod.properties ones.

Can I define System Properties within Spring Boot configuration files?

I have a single application.yml configuration file for my Spring Boot app that defines two profiles (as described in the documentation).
When the production profile is enabled, I would like to set the http.maxConnections system property to a custom value, e.g.
spring:
profiles:
active: dev
---
spring:
profiles: dev
---
spring:
profiles: production
http:
maxConnections: 15
But this doesn't actually set the system level property; it appears to just create an application-level property. I've verified this through both http://locahost:8080/env and a JMX Console when comparing launching by
java -jar -Dspring.profiles.active=production myapp.jar
versus
java -Dhttp.maxConnections=15 myapp.jar
I suppose I could create a bean that's #Conditional on the "production" profile that programmatically callsSystem.setProperty based on my application.yml-defined property, but is there a simpler way through configuration files alone?
You may try.
#Profile("production")
#Component
public class ProductionPropertySetter {
#PostConstruct
public void setProperty() {
System.setProperty("http.maxConnections", "15");
}
}
I suppose I could create a bean that's #Conditional on the "production" profile that programmatically callsSystem.setProperty based on my application.yml-defined property, but is there a simpler way through configuration files alone?
I think that's your best bet here. Spring Boot does that itself in its LoggingSystem where various logging.* properties are mapped to System properties.
Note that you'll probably want to set the system properties as early as possible, probably as soon as the Environment is prepared. To do so, you can use an ApplicationListener that listens for the ApplicationEnvironmentPreparedEvent. Your ApplicationListener implementation should be registered via an entry in spring.factories.
You can inject the environment into the constructor of the class that specifies the beans. This allows you to write application properties to the system properties before the beans are being created.
#Configuration
public class ApplicationBeans {
#Autowired
public ApplicationBeans(Environment environment) {
// set system properties before the beans are being created.
String property = "com.application.property";
System.getProperties().setProperty(property, environment.getProperty(property));
}
/**
* Bean that depends on the system properties
*/
#Bean
public SomeBean someBean() {
return new SomeBean();
}
}
You can also use PropertyPlaceholderConfigurer from org.springframework.beans.factory.config to get handle over your properties file

Loading environment specific properties file in spring

I am working on a spring-boot application, I need your assistance on below scenario.
I have properties files for each environment something like application-dev.properties, application-prod.properties etc. Is there way that my application can load environment specific properties file by using spring #Profile annotation.
Please help.
You don't need to use #Profiles annotation at all. Just use
#ConfigurationProperties(locations = "classpath:myapp-${environment.type}.properties")
and define environment type via system property. E.g. via command line -Denvironment.type=dev.
#Profile is not for loading environment specific properties file. It is for specifying profile of a bean. For example,
#Profile("dev")
#Component
class Foo {
}
It means the bean of Foo is only available when the active profiles include dev. Or the opposite #Profile("!dev"), which means the bean is available when dev is not an active profile.
So for loading environment specific properties file, since it is spring-boot, you can just specify the active profiles. There are several ways to specify the active profiles.
Environment variable: SPRING_PROFILES_ACTIVE=dev,prod
command line argument: java -jar app.jar --spring.profiles.active=dev,prod
Programmatically : SpringApplicationBuilder(...).properties("spring.profiles.active=dev,prod).run(...)
Default application.properties or yaml: spring.profiles.active:dev, prod

Categories