Spring Boot is a tool that makes developing web applications and microservices with Spring Framework faster and easier through Autoconfiguration, taking an opinionated approach to configuration and the ability to create standalone applications. But what is Autoconfiguration and what it means to take an opinionated approach?
Autoconfiguration helps developers to automatically configure beans in the Spring Context based on different conditions of the application, such as the presence of certain classes in the classpath, the existence of a bean or the activation of some property.
Understanding @Conditional
Annotation
To understand Autoconfiguration, we first need to understand @Conditional
. The Spring Framework comes with the @Conditional
annotation since version 4.0. It can be put on @Bean
methods, @Components
or even on @Configuration
and it looks like
@Conditional(SomeCondition.class)
It takes a class as a parameter which implements the interface Condition
. The parameter class should override the method
boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata)
True – Further Evaluate/Register - Create that
@Bean
,@Component
or@Configuration
False – Stop Evaluating/Registering – Don’t create that
@Bean
,@Component
or@Configuration
Let’s take an example, where we need to implement a tourism service that shows default tourism places based on the user's country.
public interface TourismService {
List<String> getTouristPlaces ();
}
Implementation of the service
public class INTourismService implements TourismService {
@Override
List<String> getTouristPlaces () {
//code impl
}
}
public class USTourismService implements TourismService {
@Override
List<String> getTouristPlaces () {
//code impl
}
}
Let’s see how to implement the Conditions based on the Country.
public class INTourismServiceCondition implements Condition {
@Override
public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
return Locale.getDefault().equals(Locale.IN);
}
}
We can have a similar implementation for the US Tourism service. Now let’s see how to apply these conditions in our configuration to load bean conditionally:
@Configuration
public class TourismConfig {
@Bean
@Conditional(INTourismServiceCondition.class)
public INTourismService inTaxCalculationService() {
return new INTourismService ();
}
@Bean
@Conditional(USTourismServiceCondition.class)
public USTourismService USTourismService () {
return new USTourismService ();
}
}
When the application is started, Spring will ensure to load the correct bean based on country (Locale in our example).
Spring Boot AutoConfiguration
To enable auto-configuration, Spring Boot uses the @EnableAutoConfiguration
annotation. Generally, we use @SpringBootApplication
. The @EnableAutoConfiguration
annotation makes it possible for Spring ApplicationContext to automatically configure itself by scanning the classpath components and registering the beans that match specific Conditions.
To load auto-configuration classes, Spring looks for META-INF/spring.factories
file within the JAR org.springframework.boot:spring-boot-autoconfigure
.
In the spring.factories
file there’s a section called # Auto Configure
. These are Spring @Configuration
with a bunch of @Conditional
annotation that Spring boot reads and tries to evaluate on every application startup.
Spring Boot comes with its own enhanced @Conditional
annotations, which eases the task of doing Autoconfiguration.
@ConditionalOnBean(CustomDataSource.class)
- The condition is true only if the user specified a@Bean
named CustomDataSource in a@Configuration
.@ConditionalOnClass(CustomDataSource.class)
- The condition is true if there is a class CustomDataSource on the classpath.@ConditionalOnCloudPlatform(CloudPlatform.AZURE_APP_SERVICE)
- The condition is true if the CloudPlatform is set to Azure app services.@ConditionalOnExpression("someExpression")
- The condition is true if the "someExpression" expression is true.@ConditionalOnJava(JavaVersion.ELEVEN)
- The condition is true if the current Java version used is 11.@ConditionalOnJndi("java:comp/env/ejb/myCustomEJB")
- The condition is true if the specified JNDI context exists.@ConditionalOnMissingBean(CustomDataSource.class)
- The condition is true if the user did not specify a@Bean
CusotmDataSource in any@Configuration
.@ConditionalOnMissingClass(CustomDataSource.class)
- The condition is true if the CustomDataSource class is not present on the classpath.@ConditionalOnNotWebApplication
- The condition is true if the application is not a web application.@ConditionalOnProperty("custom.property")
- The condition is true if custom.property is set.@ConditionalOnResource("classpath:custom.properties")
. The condition is true if custom.properties file exists in classpath.@ConditionalOnSingleCandidate(CustomDataSource.class)
- The condition is true if there is exactly one primary CustomDataSource bean specified in the application.@ConditionalOnWebApplication
- The condition evaluates true if the application is a web application.
Summary
When a Spring Boot application starts:
It reads the .properties file and the other 17 hard coded locations to look what autoconfiguration needs to be enabled.
It also reads in the spring.factories file of autoconfigure-module and finds out which AutoConfiguration it should evaluate.
It has enhanced @Conditional annotation which helps to ease auto-configuration.