Spring Boot Auto Configuration

For Spring Boot application, we are using the @SpringBootApplication annotation. Inside @SpringBootApplication there is @EnableAutoConfiguration annotation. As mentioned in previous article - Spring Boot Web Application Example that @SpringBootApplication = @SpringBootConfiguration + @EnableAutoConfiguration + @ComponentScan

...
@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan(...)
public @interface SpringBootApplication {
   ...
}
                    

The @EnableAutoConfiguration annotation enables the auto-configuration of Spring ApplicationContext by scanning the classpath components and registers the beans that are matching various Conditions. In short: to enable the auto-configuration magic, Spring Boot uses the @EnableAutoConfiguration annotation

The Old Ways

If you build a "normal" Spring application, you need to configure number of things. Here some that I can think of:

  • Component scan
  • Connection pool and database configuration
  • Transaction Manager
  • If you are using Spring MVC, we need to configure dispatcher servlet, a view resolver, etc

As example, here configurations from non Spring Boot application:

<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" xmlns:p="http://www.springframework.org/schema/p" xmlns:tx="http://www.springframework.org/schema/tx" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd"> <context:property-placeholder location=" classpath*:jdbc.properties, classpath*:jdbc.${spring.profiles.active}.properties " /> <tx:annotation-driven /> <bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close" p:driverClassName="${jdbc.driver}" p:url="${jdbc.url}" p:username="${jdbc.username}" p:password="${jdbc.password}" p:maxWait="40000" p:maxActive="80" p:maxIdle="20" /> <bean class="org.springframework.orm.jpa.JpaTransactionManager" id="transactionManager"> <property name="entityManagerFactory" ref="entityManagerFactory" /> <property name="jpaDialect"> <bean class="org.springframework.orm.jpa.vendor.HibernateJpaDialect" /> </property> </bean> <bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean"> <property name="dataSource" ref="dataSource" /> <property name="packagesToScan" value="com.dariawan.todo.domain" /> <property name="jpaVendorAdapter"> <bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter"> <property name="databasePlatform" value="${hibernate.dialect}" /> <property name="showSql" value="false" /> <property name="generateDdl" value="false" /> </bean> </property> <property name="jpaProperties"> <props> <prop key="hibernate.format_sql">true</prop> </props> </property> </bean> <bean id="sessionFactory" factory-bean="entityManagerFactory" factory-method="getSessionFactory" /> <bean id="messageSource" class="org.springframework.context.support.ResourceBundleMessageSource"> <property name="basenames"> <list> <value>messages</value> </list> </property> </bean> </beans>

And next is the database configuration properties:

# DB Config hibernate.dialect = org.hibernate.dialect.MySQL5InnoDBDialect jdbc.driver = com.mysql.jdbc.Driver jdbc.url = jdbc:mysql://localhost/todo?autoReconnect=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull jdbc.username = barista jdbc.password = espresso

Spring Boot Auto-configure

Spring Boot auto-configuration automatically configure a Spring application based on the dependency classes present on the classpath and create and wires necessary beans for us. This feature work like magic and happens silently in the background.

Behind the scene, this automatic start, load and wire are based on the conditional matches. The see this clearly, we can enable auto-configuration report for our Spring Boot application. Set DEBUG for springframework logging level in the application.properties file:

logging.level.org.springframework: DEBUG

Once you run the application, you may notice similar output in the console:

============================ CONDITIONS EVALUATION REPORT ============================ Positive matches: ----------------- AopAutoConfiguration matched: - @ConditionalOnClass found required classes 'org.springframework.context.annotation.EnableAspectJAutoProxy', 'org.aspectj.lang.annotation.Aspect', 'org.aspectj.lang.reflect.Advice', 'org.aspectj.weaver.AnnotatedElement' (OnClassCondition) - @ConditionalOnProperty (spring.aop.auto=true) matched (OnPropertyCondition) AopAutoConfiguration.CglibAutoProxyConfiguration matched: - @ConditionalOnProperty (spring.aop.proxy-target-class=true) matched (OnPropertyCondition) CodecsAutoConfiguration matched: - @ConditionalOnClass found required class 'org.springframework.http.codec.CodecConfigurer' (OnClassCondition) CodecsAutoConfiguration.JacksonCodecConfiguration matched: - @ConditionalOnClass found required class 'com.fasterxml.jackson.databind.ObjectMapper' (OnClassCondition) CodecsAutoConfiguration.JacksonCodecConfiguration#jacksonCodecCustomizer matched: - @ConditionalOnBean (types: com.fasterxml.jackson.databind.ObjectMapper; SearchStrategy: all) found bean 'jacksonObjectMapper' (OnBeanCondition) DataSourceAutoConfiguration matched: - @ConditionalOnClass found required classes 'javax.sql.DataSource', 'org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseType' (OnClassCondition) DataSourceAutoConfiguration.PooledDataSourceConfiguration matched: - AnyNestedCondition 1 matched 1 did not; NestedCondition on DataSourceAutoConfiguration.PooledDataSourceCondition.PooledDataSourceAvailable PooledDataSource found supported DataSource; NestedCondition on DataSourceAutoConfiguration.PooledDataSourceCondition.ExplicitType @ConditionalOnProperty (spring.datasource.type) did not find property 'type' (DataSourceAutoConfiguration.PooledDataSourceCondition) - @ConditionalOnMissingBean (types: javax.sql.DataSource,javax.sql.XADataSource; SearchStrategy: all) did not find any beans (OnBeanCondition) DataSourceConfiguration.Hikari matched: - @ConditionalOnClass found required class 'com.zaxxer.hikari.HikariDataSource' (OnClassCondition) - @ConditionalOnProperty (spring.datasource.type=com.zaxxer.hikari.HikariDataSource) matched (OnPropertyCondition) - @ConditionalOnMissingBean (types: javax.sql.DataSource; SearchStrategy: all) did not find any beans (OnBeanCondition) <... purposely truncated ...> Negative matches: ----------------- ActiveMQAutoConfiguration: Did not match: - @ConditionalOnClass did not find required class 'javax.jms.ConnectionFactory' (OnClassCondition) AopAutoConfiguration.JdkDynamicAutoProxyConfiguration: Did not match: - @ConditionalOnProperty (spring.aop.proxy-target-class=false) did not find property 'proxy-target-class' (OnPropertyCondition) <... purposely truncated ...> Exclusions: ----------- None Unconditional classes: ---------------------- org.springframework.boot.autoconfigure.context.ConfigurationPropertiesAutoConfiguration org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoConfiguration org.springframework.boot.autoconfigure.info.ProjectInfoAutoConfiguration

In the report, Spring Boot provides details about which configurations are matching (Positive matches) and which are excludes (Negative matches) and what condition behind.

Let’s take the example of the DataSourceAutoConfiguration in the "positive match" section. Spring Boot found required classes 'javax.sql.DataSource' and 'org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseType' OnClassCondition:

@Configuration
@ConditionalOnClass(value = {DataSource.class, EmbeddedDatabaseType.class})
@EnableConfigurationProperties(value = {DataSourceProperties.class})
@Import(value = {DataSourcePoolMetadataProvidersConfiguration.class, DataSourceInitializationConfiguration.class})
public class DataSourceAutoConfiguration {
   ...
}
                    

Based on this match Spring Boot auto-configuration will load the DataSource configuration for our application.

Disabling Auto-Configuration Classes

If we wanted to exclude the auto-configuration from being loaded, we could set spring.autoconfigure.exclude property it the application.properties file. Let say I want to exclude Spring Security auto-configuration from my application:

spring.autoconfigure.exclude=org.springframework.boot.autoconfigure.security.servlet.SecurityAutoConfiguration,\ org.springframework.boot.autoconfigure.security.servlet.SecurityFilterAutoConfiguration

And after some change (exclude my WebSecurityConfig class too), here the result in the report when we run this application

============================ CONDITIONS EVALUATION REPORT ============================ Positive matches: ----------------- <... purposely truncated ...> Negative matches: ----------------- <... purposely truncated ...> Exclusions: ----------- org.springframework.boot.autoconfigure.security.servlet.SecurityAutoConfiguration org.springframework.boot.autoconfigure.security.servlet.SecurityFilterAutoConfiguration Unconditional classes: ---------------------- <... purposely truncated ...>

You can see that those two classes now part of "Exclusions"