Multi-file config for Spring Boot app - java

So, I have a Spring Boot application that is based on a plugin architecture, with its config properties, as you would expect, in an application.yml. Due to the fact that plugins may or may not be enabled however, I am keeping the config for each plugin in a separate file.
What's more, I would like to differentiate between these files (e.g. by naming them differently - preferably after the name of the plugin itself) and not have them all as application.yml.
I know that I can use spring.config.name to add the names of all the property files, depending on what plugin is enabled, but I would like a more dynamic approach.
For example, a config directory, with an application.yml and sub-folders named after each plugin - with a separate application.yml in each one...
Ideally, I would then just set spring.config.location to the path of the config folder and Spring would pick up all these files, by looking up in the sub-folders recursively.
So, my question to you, dear Spring experts, is: what magic dust do I have to sprinkle on my config to make this happen?
Is there any other approach you would recommend I take?

Related

How to merge application.properties with application-default.properties and include in other test profiles with Spring Boot >2.4

We would like to merge src/main/resources/application.properties with additional default properties when running tests which in turn should be included by other (test) properties files activated via specific profiles in our Spring Boot application.
Up until Spring Boot 2.4 this worked quite well by having all common test properties in src/test/resources/application-default.properties to keep things DRY. Those were then automatically merged with the ones from src/main/resources/application.properties by Spring [1]. This allowed us to have our own set of default properties without requiring tests to specify an #ActiveProfiles("default").
Other (test) profiles could then have their own application-<profile>.properties with spring.profiles.include=default and then further extend the defaults.
With Spring Boot 2.4 I'm struggling with the new "rules":
I can no longer load application-default.properties from application-<profile>.properties since spring.profiles.include is no longer allowed in non profile-specific documents [2].
I don't want to introduce a src/test/resources/application.properties since I don't want to repeat everything from src/main/resources/application.properties. Also I don't want to load any activate any test-related profiles in the app's properties.
It looks like one solution could be to explicitly add spring.profiles.include=default to src/main/resources/application.properties to force the application to include the properties file with default properties which will work as before when it comes to running the actual application but consider src/test/resources/application-default.properties when running the tests.
Is this the way to go or are there smarter solutions to tackle this problem and still keep the properties free of redundancies?
spring.profiles.active=dev
add this config in application.properties file

How to integrate spring profiles in Spring Boot 2.4+ application.properties

My current spring boot 2.3 and below config files are
application.properties
application-dev.properties
application-qa.properties
application-prod.properties
application-local.properties
I have to include the profile onlyLocal in my local profile and I have to include cloudProfile in all other profiles.
For spring boot 2.4+, I found that putting the below in my application.properties file works:
spring.profiles.group.local=local,onlyLocal
spring.profiles.group.dev=dev,cloudProfile
spring.profiles.group.qa=qa,cloudProfile
spring.profiles.group.prod=prod,cloudProfile
My question is, is there a better/cleaner way?
Using groups to aggregate multiple profile files into one profile is perfectly sound and agrees very nicely with the intentions of the Spring Boot team: https://spring.io/blog/2020/08/14/config-file-processing-in-spring-boot-2-4
Generally, you should think about whether the complexity of profile groups is really worth it. If the profiles cloudProfile and onlyLocal only yield a handful of properties, then it might make more sense to just copy them into the respective properties files. If the two profiles do contain a lot of properties, then the complexity is warranted and allows you to avoid duplication.
Another mechanism to import properties files into other properties files is using spring.config.import. But it's really doing the same with a different mechanism.

Separate properties file for multiple environments

I am trying to have separate property files for prod and dev environment.
I have two property files application-prod.properties, application-dev.properties placed in classpath:/config
I added VM option -Dspring.profiles.active=dev
According to what I understand from the documentation and many other references on the web, on accessing Spring Environment as environment.getProperty("") the property in "application-dev.properties" should be loaded. However, I am getting null and as it seems the property files are not read by Spring.
I also tried defining both the files in #PropertySource. Doing this, the file defined second is picked up and the corresponding property is returned. Spring is not choosing the file based on the active profile.
Am I missing something?
I also came across a issue raised through some SO questions, but I am not sure if it refers to the same problem.
Right, so documentation you are pointing to is from Spring Boot project. That is not the same as Spring Framework. If you are not using Spring Boot, -Dspring.profiles.active=dev wouldn't work.
You have two options:
Introduce Spring Boot to your project ans turn on auto-configuration (#SpringBootApplication or #EnableAutoConfiguration).
Use plain Spring Framework features like PropertyPlaceholderConfigurer, but it doesn't give you same flexibility as Spring Boot features and you will need to create some boilerplate code to handle various envs.

How to configure Spring to load application.properties from outside of jar?

I'd like to have a directory structure as so:
/Directory
- Application.jar
- application.properties
So that I can change properties without having to repackage and redeploy (and instead just restarting the jar). How can I accomplish this with spring annotations or configuration classes?
I'm not asking about making external resources available with my web application, I'm also looking to change the location from where spring loads the application.properties file.
You're mentioning jar, so you're using Spring Boot?
If so, external application.properties in the same directory (structure just like you described) will override application.properties packaged inside the jar file.
Then, if you have something like key=value in your application.properties, you can inject it in your code with #Value("${key}") String key.
Try it, it will just work :)
You may want to explore PropertyPlaceholderExplorer class in Spring. This class provides the facility to access the properties file external to your jar/war bundle. There is a short nice tutorial on this as well here.
If you start using Spring Boot (at some stage you for sure will). you get powerful configuration externalization features.
With Spring Boot your applications.properties are automatically loaded into Spring Boot context and you can use ${...} placeholders.
You can use even more modern feature #ConfigurationProperties to map you configuration to POJO. This POJO can even be validated by Java EE validation annotations (e.g. #NotNull)

Spring .properties files purpose

I read #yorkw answer at this topic. He said:
The purpose of .properties file is to provide the capability of
configuring database connections at application runtime (for web
application, usually require restarting application container/server
after .properties file changes).
The question is if we can change properties on the fly without restarting container/server? Provide me an example please (I ask because in my demo it doesn't work, means value isn't changed).
I mean if we have some kind of admin tool than we can move all our configured settings to .properties files and change them via that admin tool.
Spring property files are designed to change the Spring Config of an application. The spring config is read when the spring container is initialised - this will form part of the application startup.
If a change is made to one of the spring config files (includes the *.properties files) the spring container would need to be reloaded to pick up the change.
Properties put into spring properties files should typically be properties that are tied to the life cycle of the application - i.e. the kind of properties that when changed require an application/spring container re-initialised - things like the database url/config etc.
So values that you want to change at runtime without requiring a restart of the application are not good candidates for placement in a spring properties file.

Categories