Spring Boot AutoConfiguration

Spring Boot AutoConfiguration

The magic behind Spring Boot

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:

  1. It reads the .properties file and the other 17 hard coded locations to look what autoconfiguration needs to be enabled.

  2. It also reads in the spring.factories file of autoconfigure-module and finds out which AutoConfiguration it should evaluate.

  3. It has enhanced @Conditional annotation which helps to ease auto-configuration.