Reputation: 450
I'm building multiple Spring Boot applications which will be deployed on the same servlet container. But I'm having difficulties getting Spring Boot to work with externalized configuration files the way I want, and not like the framework wants.
Situation:
spring.config.location
Problem:
As the applications are deployed on the same JVM, the property spring.config.location
has the same value for all applications. I want our applications to all use the same configuration file naming (application.properties), so specifying spring.config.name
is not an option.
What I would like:
spring.config.name
as the configuration name should be standardized accross all our applications (constant)organizing configuration files in a per-application directory layout:
${spring.config.location}/app1/application.properties ${spring.config.location}/app2/application.properties ${spring.config.location}/app3/application.properties
Questions:
Is there some mechanism to influence or override loading or resolving of external configuration files?
Are there other approaches to get the desired result?
Upvotes: 3
Views: 2783
Reputation: 450
The suggestions of @Iulian Rosca to use a pattern like ${properties_home}/${application_id}/application.properties
brought me to the idea of defining a custom JVM property like app.config.root
and using this property to override spring.config.location
very early in the application lifecycle.
My application class looks now like this and works for embedded and container deployments:
@SpringBootApplication
public class Application extends SpringBootServletInitializer {
@Override
protected SpringApplicationBuilder configure(SpringApplicationBuilder builder) {
return configureApplication(builder);
}
public static void main(String[] args) {
configureApplication(new SpringApplicationBuilder()).run(args);
}
private static SpringApplicationBuilder configureApplication(SpringApplicationBuilder builder) {
return builder
.sources(Application.class)
.properties("spring.config.location:${${app.config.root}/myapp1/:#{null}}");
}
}
Important notes to this solution:
app.config.root
has to be set externally by JVM or JNDI propertyapp.config.root
can only contain a single external configuration path (for my requirements this was sufficient) in contrast to spring.config.location
where multiple comma-separated paths can be specifiedSpringApplicationBuilder.properties(...)
sets the application's default properties. Because of this, spring.config.location
cannot be specified externally anymore, as JVM or JNDI Properties have priority over default properties and would therefore override spring.config.location
again.Upvotes: 0
Reputation: 1015
You can achieve what you're trying by using @PropertySource
. According to the official documentation (Externalized Configuration) you can use this annotation to externalize configuration files, e.g.:
@Configuration
@PropertySource("file:/path/to/application.properties")
public class AppConfig {
}
As stated in here, inside @PropertySource
you can use placeholders that would be resolved against other property sources, for e.g. values declared in application.properties
Assuming that "my.placeholder" is present in one of the property sources already registered, e.g. system properties or environment variables, the placeholder will be resolved to the corresponding value. If not, then "default/path" will be used as a default. Expressing a default value (delimited by colon ":") is optional. If no default is specified and a property cannot be resolved, an IllegalArgumentException will be thrown.
You can declare properties_home
as an environment variable and application_id
inside your application.properties
file.
@Configuration
@PropertySource("${properties_home}/${application_id}/application.properties")
public class AppConfig {
}
Don't forget to enable support for resolving the placeholders:
In order to resolve ${...} placeholders in bean definitions or @Value annotations using properties from a PropertySource, one must register a PropertySourcesPlaceholderConfigurer. This happens automatically when using in XML, but must be explicitly registered using a static @Bean method when using @Configuration classes.
Update:
In order to override the properties from the external file you could use a spring profile. Inside the packaged application.properties you need to set:
spring.profiles.active=external
Declare all the properties that you want to take precedence as part of the external profile inside the file located in "${properties_home}/${application_id}/application.properties"
.
Upvotes: 3