Demystifying Spring Boot Autoconfiguration
Hi random reader.
In this article i want to talk a bit about the feature of “Spring Boot”, that can be considered as the main reason for it being the top framework among modern Java developers.
The feature that gives it’s users ability to automagically get preconfigured feature rich Spring Beans, without the need to waste time on configuring every little detail by hand.
The feature i am talking about is called “Autoconfiguration” and it’s concrete initiator in code is annotation: @Autoconfiguration. JusRight before diving in, just to make you understand how cool it really is, let me cite sentence from one very popular book about Java and Spring Framework:
“Spring Boot’s @EnableAutoconfiguration - This humble little annotation might as well be named @Abdracadabra because it’s one line of configuration that enables the magic of Spring Boot auto-configuration. This one line keeps you from having to write the pages of configuration that would be required otherwise.”
So what is this “Autoconfiguration” all about?
To fully understand the mechanism of auto configuration let’s first consider steps, needed for getting fully set up beans in vanilla Spring(without Boot). This way we can clearly see the repetitive steps that we’ll avoid when using Spring Boot’s auto configuration mechanism.
Let’s say in my project i need to persist some data to an arbitrary database. The intuitive part for this problem would be to add as a dependency library of a needed database and configure DataSource bean of it( I hope you know the details and the usage of DataSource objects in Java if no, please follow the link to get more information about it. ) to be able to inject it into some “Data Acess Object” class and be able to use Persistence logic in let’s say Service beans. As a user of Vanilla Spring Framework these are the steps you’ll need to get fully configured and ready to use DataSource bean:
- Include the concrete dependency of use-case specific storage in the build file( pom.xml for Maven or build.gradle for Gradle ) to get the access to the concrete DataSource implementation.
- Configure a Spring Bean for use-case specific Datasource using @Configuration and @Bean annotations, which are available from Spring dependency, and specify properties depending on business rules/needs.
After completing these two steps we’ll have fully functional DataSource Bean in the Application Context, which we’ll be able to easily inject and use in any other Spring Bean.
Yey !!! This was so cool !!! IMHO Writing configurations are the funniest part of programming !!! Isn’t it ???
Hmmm, nope… Not at all…Defenitely not.
Let’s all agree, that even though configuration process is absolutely inevitable ( like Thanos the Titan from Marvel Cinematic Universe), it isn’t cool or fun at all. Some even may consider it as a waste of time. And they might be right, because for a software Engineer every minute spent on configuration is every minute not spent on solving the Business problems. Which, well, is no good for business.
I deeply believe that in our universe, there exists no software engineer, who enjoys writing any kind of configurations.
Let me introduce you a statement that Spring Boot follows: For a developer real fun and challenge begins when it’s time to use configured beans not during the configuration process.
Don’t you agree with it?
So let’s take our time, not to just follow those steps of configuration above, but think through them. Since it’s well known that using something in practice might be thousand times better than just listening a random dude’s words about it, I strongly encourage you to, stop reading this article at this current moment. Open your IDE and try to configure Spring Beans from different dependencies following two steps stated above.
If you followed my advice above you might have noticed an emerging common pattern between all these configurations of different beans: No matter what the dependency is, the two step configuration process above is mostly valid for all of them. That’s exactly what Spring Team noticed and as a result we got the formulation of an “Autoconfiguration” mechanism and the notion of “Starters”:
“What if for each and every dependency “X”, that might be applicable to the pattern of configuration above, we create a new seperate ‘Parent’ dependency which we call “X-Starter” and which will have a transitive dependency on “X” itself and all other needed configuration jars. And lastly, it will also have configuration code snippets, with @Configuration and @Bean annotations in them.
For any arbitrary user of our X-Starter library, simply addition of X-Starter as a dependency of a project is needed to have fully ready to use and fully configured spring beans. Since, as you already guessed, X-Starter will pull all the transitive dependencies and the result is that the user of our new dependency will not have to write all the boiler plate code of configurations themselves.”
For the statement above to become clearer and more concrete, let’s translate it into our concrete use case of DataSource-s, stated above.
The situation will be next: There will be a new “DataSource-Starter” dependency, which itself will have a dependency of the “DataSource” and all other needed configurations ( including all @Configuration and @Bean code snippets ).
In the future everyone who will need a datasource in their project will just have to include “DataSource-Starter” dependency and will automatically have two step configuration mechanism present in the project. Ualla!
Well, let’s be honest. The statement present above is kind of a win situation.
Engineers don’t have to write repetitive lines of code for configurations. More time will be spent on solving business problems for clients. And as a result, everyone, including clients, management and engineering team, is happy.
Cool, are we done here ?
Well, to tell the truth, we have one more detail to cover.
For the sake of simplicity i skipped one very important and IMHO very interesting point, which we’ll cover in depth now.
As you probably know, for a @Configuration class to be noticed by the Spring’s Application context, according package(s) of this configuration class should be scanned by Spring Boot, using @ComponentScan or similar mechanisms. Fortunately Spring team has our backs covered in this case too. By default upon importing the starter dependency in a Spring Boot project, Spring scans each and every starter dependency for spring.factories file under the META-INF directory. In this file the list of all configuration classes are present so , this way each and every starter dependency has a centralized place for all of the configurations.
If you followed me to this point i have a good news, it’s definitely all now. No more details to cover !
IMHO, We covered nearly all the parts that is under the hood of Spring’s autoconfiguration mechanism. I deeply hope, that this concrete article will help us to understand and appreciate how crucial of a technology it is. Literally every modern Java developers needs to know the details of this technology and who knows? Maybe in the future we’ll see more cool technologies like this.
Thanks for reading;)