As part of Spring Boot tutorial, in this post, we will see how Spring Boot auto-configuration works. We will have a greater look at the auto-configurations internals.
Introduction
Spring Boot auto-configuration automatically configure a Spring application based on the dependencies present on the classpath. Spring Boot detects classes in the classpath and auto-configuration mechanism will ensure to create and wires necessary beans for us. This is one of the most powerful feature of the Spring Boot and most of the work happens silently in the background.
1. Auto-Configuration Report
Before we get in to the details, let’s enable auto-configuration report for our Spring Boot application. You can create a simple Spring Boot application using initializr. Set the debug=true
in the application.properties
file. Once you run the application, you may notice similar output in the console:
============================
CONDITIONS EVALUATION REPORT
============================
Positive matches:
-----------------
CodecsAutoConfiguration matched:
- @ConditionalOnClass found required class 'org.springframework.http.codec.CodecConfigurer' (OnClassCondition)
ErrorMvcAutoConfiguration.WhitelabelErrorViewConfiguration#defaultErrorView matched:
- @ConditionalOnMissingBean (names: error; SearchStrategy: all) did not find any beans (OnBeanCondition)
JacksonHttpMessageConvertersConfiguration.MappingJackson2HttpMessageConverterConfiguration matched:
- @ConditionalOnClass found required class 'com.fasterxml.jackson.databind.ObjectMapper' (OnClassCondition)
- @ConditionalOnProperty (spring.http.converters.preferred-json-mapper=jackson) matched (OnPropertyCondition)
- @ConditionalOnBean (types: com.fasterxml.jackson.databind.ObjectMapper; SearchStrategy: all) found bean 'jacksonObjectMapper' (OnBeanCondition)
...............................................................................................................................................................................
Negative matches:
-----------------
ActiveMQAutoConfiguration:
Did not match:
- @ConditionalOnClass did not find required class 'javax.jms.ConnectionFactory' (OnClassCondition)
AopAutoConfiguration:
Did not match:
- @ConditionalOnClass did not find required class 'org.aspectj.lang.annotation.Aspect' (OnClassCondition)
...............................................................................................................................................................................
Exclusions:
-----------
None
Unconditional classes:
----------------------
org.springframework.boot.autoconfigure.context.ConfigurationPropertiesAutoConfiguration
org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoConfiguration
As clear in the above output, Spring Boot provides details about what all configuration are matching and what are excludes (which does not match) and what was the reason for this action. Based on these matches, spring boot auto-configuration will start, load and wire the configurations.
Let’s take the example of the JacksonHttpMessageConvertersConfiguration
in the “positive match” section. Spring Boot finds the ObjectMapper in the class path (I am using a web application for this example), based on this match spring boot auto-configuration will load the Jackson configuration for our application.
2. Understanding @Conditional Annotation
Before we get into details of how Spring Boot auto-configuration works, let’s take a broader look at the @Conditional
annotation. This annotation is the base and most annotations used by the Spring Boot auto-configuration are extensions of this annotation. The @Conditional
annotation introduced in Spring 4 is an improvement to the Spring profile feature. It adds flexibility to the developer to register beans based on several conditions like:
- A type-level annotation on any class directly or indirectly annotated with @Component, including @Configuration classes.
- As a meta-annotation, for the purpose of building custom stereotype annotations.
- Method-level annotation on any @Bean method.
Let’s pick an example, where we need to implement a tax rate service based on user country. Let’s examine how our code base looks like:
public interface TaxCalculationService{
Double getTaxRate();
}
This is our TaxCalculationService implementation detail
public class USTaxCalculationService implements TaxCalculationService{
@Override
public Double getTaxRate(){
// Tax rate for US
}
}
public class CATaxCalculationService implements TaxCalculationService{
@Override
public Double getTaxRate(){
// Tax rate for Canada
}
}
Let’s carry out the condition based on the user country:
public class USTaxCalculationTypeCondition implements Condition {
@Override
public boolean matches(ConditionContext conditionContext, AnnotatedTypeMetadata metadata) {
return Locale.getDefault().equals(Locale.US);
}
}
We can have an identical implementation for the Canadian tax service. Let’s look at how to apply these conditions in our configurations to load beans conditionally:
@Configuration
public class AppConfig {
@Bean
@Conditional(USTaxCalculationTypeCondition.class)
public TaxCalculationService usTaxCalculationService() {
return new USTaxCalculationService();
}
@Bean
@Conditional(CATaxCalculationTypeCondition.class)
public TaxCalculationService caTaxCalculationService() {
return new CATaxCalculationService();
}
}
If we run our application, Spring will ensure to load the correct bean based on country (Locale in our example). Now we have the key knowledge of The @Conditional
annotation,let’s learn how Spring Boot use this feature for the auto-configuration.
3. Understanding Auto-configuration
Internally auto-configuration is achieved with @Configuration
annotation. Let’s look at the out of the box JacksonAutoConfiguration
for a further understanding:
@Configuration
@ConditionalOnClass({ObjectMapper.class})
public class JacksonAutoConfiguration {
// auto-configuration stuff
}
Spring Boot, use the @Conditional
annotations to determine if it require setting up auto-configuration for the configuration or not. Usually auto-configuration classes use the following conditional annotations:
@ConditionalOnClass
@ConditionalOnMissingBean
Out of the box, Spring provides plenty of conditional annotations.Please consult reference documentation
3.1 The @ConditionalOnClass Annotation
The class conditions are the most common conditional annotation use by auto-configuration for the detection. The @ConditionalOnClass
annotation allows it to include the configuration class based on a specific class. Here is our JacksonAutoConfiguration
configuration class:
@Configuration
@ConditionalOnClass({ObjectMapper.class})
public class JacksonAutoConfiguration {
// auto-configuration stuff
}
In this example, Spring Boot auto-configuration includes JacksonAutoConfiguration, if it finds Object mapper in the classpath. We can likewise use the @ConditionalOnMissingClass
annotation to enable configuration if the class is missing in the classpath.
3.2 The @ConditionalOnMissingBean Annotation
We use this annotation to verify the absence of a specific bean. Let’s look at the example for a better insight:
@Configuration
@ConditionalOnClass({ObjectMapper.class})
public class JacksonAutoConfiguration {
// additional configuration code
@Bean
@Primary
@ConditionalOnMissingBean
public ObjectMapper jacksonObjectMapper(Jackson2ObjectMapperBuilder builder) {
return builder.createXmlMapper(false).build();
}
}
In above example, it will create the ObjectMapper bean if it already contains no bean of type ObjectMapper in the ApplicationContext
. The other annotation @ConditionalOnBean
works opposite to the @ConditionalOnMissingBean
annotation.
4. Spring Boot Auto-Configuration
To enable the auto-configuration magic, Spring Boot uses the @EnableAutoConfiguration
annotation. Normally we use the @SpringBootApplication
annotation which includes our @EnableAutoConfiguration
annotation. The @EnableAutoConfiguration annotation enables the auto-configuration of Spring ApplicationContext by scanning the classpath components and registers the beans that are matching various Conditions.
4.1 Locating Auto-configuration Classes
To load auto-configuration classes, Spring needs to know where to look for it. Spring checks META-INF/spring.factories
file within your published jar. This file should contain a list of the configuration class. Let’s look at the spring.factories
file under the auto-configuration jar
# Auto Configure
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
org.springframework.boot.autoconfigure.admin.SpringApplicationAdminJmxAutoConfiguration,\
org.springframework.boot.autoconfigure.aop.AopAutoConfiguration,\
org.springframework.boot.autoconfigure.amqp.RabbitAutoConfiguration,\
This is a standard component of the Spring Core and it uses SpringFactoriesLoader
, get the list of Java Configurations classes configured using the org.springframework.boot.autoconfigure.EnableAutoConfiguration
property key.
5. Custom Auto-Configuration
To get a further understanding, I firmly suggest reading Custom Starter with Spring Boot
Summary
In this article, we saw how Spring Boot auto-configuration works. We examined how Spring Boot uses the @Conditional
annotation and SpringFactoriesLoader
feature to implement auto-configuration.