30 January 2019

Recently, while working on a job, I ran into an interesting problem with Spring Boot: the configuration files I had defined using the @PropertySource annotation were being overridden by the application.properties file, which I had also defined with a @PropertySource annotation. Why wasn't Spring prioritizing my configuration files correctly?

What I was attempting to accomplish was shipping my jar with some default configuration options that were mostly tailored for my local development setup, and then being able to specify an external configuration file for staging and production that would override the values accordingly. I got the idea from a project I used from GitHub called Acrarium, but unfortunately I didn't quite take the time to slow down and understand what was going on before attempting to implement something similar myself.

I came to the realization that something was wrong because while testing deployments with some docker containers locally, my Spring Boot app was crashing since it couldn't connect to the databse. I spent hours trying to figure out why Spring Boot container couldn't connect to the MySQL container, going as far as installing the MySQL command line client to manually verify that the containers were in fact connected and able to communicate with each other. That of course wasn't the problem, so I took to StackOverflow to find some answers.

I discovered that you can pass in an argument to the application while running it as a jar, specifically -spring.config.location, and while it fixed my issue, I wasn't satisfied with this because I still didn't understand what the original problem was, and I wasn't content to just shrug my shoulders and move along. It was only through searching around a bit more that I stumbled upon the Spring Boot documentation page for externalized configuration when I realized my mistake. If you look towards the bottom of this list, item #15 at the time of writing, is the application.properties file and following it with one level lower in priority for Spring, is the @PropertySource annotation configuration files.

The solution, then, was to rename my application.properties file to something else, and add that new file inside another @PropertySource annotation on my Application class, and problem solved! Yet another case of the problem lying between the chair and keyboard. Had I read through the source a little closer with the Acrarium project, from which I took the inspiration for this setup, I would have noticed that they weren't using the application.properties file to define overridable defaults, but rather a default.properties file. Lesson learned here: slow down and read the source, make sure you understand it and can explain what's going on, and then try to imitate it in your own works.