Spring Boot Auto Configuration

By | | Updated : 2019-12-27 | Viewed : 340 times

Spring Boot Auto-configuration

The current article helps you to understand of Spring Boot Auto Configuration mechanism with some simple examples. Here we will learn about internal mechanism of the Auto Configuration and its necessity.

Auto Configuration Necessity

Typically, the Spring application is required many configurations i.e., configurations that are required for Spring MVC Dispatcher Servlet, View resolvers, and other required jar classes. Please consider a SpringMVC application with Hibernate. Here below-shown configurations are required. Please look into those configurations to implement the Spring MVC Application.

Below provided configuration is for Web.xml where DispatcherServlet configured.

Example snippet for web.xml
 <servlet>
    <servlet-name>spring-dispatcher</servlet-name>
    <servlet-class>org.springframework.web.servlet.DispatcherServlet
      </servlet-class>
    <load-on-startup>1</load-on-startup>
  </servlet>
  
  <servlet-mapping>
    <servlet-name>spring-dispatcher</servlet-name>
    <url-pattern>/</url-pattern>
  </servlet-mapping>

Please find the below-given XML configuration for spring-dispatcher-servelet.xml

Example snippet for spring-dispatcher-servlet.xml
<context:component-scan base-package = "com.docsconsole.tutorials.springmvc.*" />

<bean class = "org.springframework.web.servlet.view.InternalResourceViewResolver">
  <property name = "prefix" value = "/WEB-INF/views/" />
  <property name = "suffix" value = ".jsp" />
</bean>

If the application needs Hibernate Configurations then below-given configuration should be added.

Example snippet for hibernate-config.xml
<beans:bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
	<beans:property name="driverClassName" value="com.mysql.jdbc.Driver" />
	<beans:property name="url" value="jdbc:mysql://localhost:3306/TestDB" />
	<beans:property name="username" value="XXXXXXX" />
	<beans:property name="password" value="XXXXXXX" />
</beans:bean>


<beans:bean id="hibernate4AnnotatedSessionFactory"
	class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
	<beans:property name="dataSource" ref="dataSource" />
	<beans:property name="annotatedClasses">
		<beans:list>
			<beans:value>com.docsconsole.springmvc.model.Author</beans:value>
		</beans:list>
	</beans:property>
	<beans:property name="hibernateProperties">
		<beans:props>
			<beans:prop key="hibernate.dialect">org.hibernate.dialect.MySQLDialect
			</beans:prop>
			<beans:prop key="hibernate.show_sql">true</beans:prop>
		</beans:props>
	</beans:property>
</beans:bean>

So many configuraions are required for Spring MVC applciation. But if we use Spring Boot these are all configured automatically.

Auto Configuration

Spring Boot has brought up a new idea to automate the configuration part. Auto-Configuration in Spring Boot automatically configures all the dependencies for an application. Here Spring Boot will find classes in the classpath and start Auto Configuration. So beans will be registered here in Application Context for the instantiation with wiring up required beans. Here Bean registration will be done based on some conditions.

This powerful feature is very helpful for implementation and making the developer's life easy that it is not required configurations. And we can implement customized starters that would handle customized configuration automatically.

How does AutoConfiguration work?

The magic of autoconfiguration is with annotation called @EnableAutoConfiguration. Here @EnableAutoConfiguration enables the auto-configuration by scanning of specific classes classpath. If required classes are in the classpath then registration of that classes will be triggered.

Implementation of Auto Configuration

We will learn here the way of the working mechanism of Spring Boot's Auto Configuration. Before that, we will understand the @Profile and @Conditional annotation in Spring.

@Profile Annotation

Sometimes Spring beans registration is required based on the type of environment. Suppose in Dev the DB properties should point to Dev Database only whereas in Production these properties should be production Database.

So To achieve these we must separate all the properties as seperate file per the environment means each separate environment must have a separate config file. Spring has introduced to resolve this problem with @Profile.

Example of @Profile
@Configuration
public class AppConfig
{
 	@Bean
 	@Profile("DEV")
	 public DataSource devDataSource() {
	
	}
}

By specifying the System Property -Dspring.profiles.active=DEV the profile will be activated accordingly. So DataSource bean will be registered for instantiation. While instantiating the DataSource Bean, The profile values will be assigned to the object. The same way we can use instantiated the DataSource Bean for production. But values will be changed for DataSource bean for production.

@Conditional Annotation

This is introduced in Spring to add additional flexibility to @Profile. Because @Profile will be used to enable/disable Spring beans registration based on the activated profile. But it is not sufficient to register the beans. It should be based on some conditions.

    So registration can be done based on the following conditions.

  • Register a bean If a Class has existed in ClassPath.

  • Register a bean If a Class is not registered with ApplicationContext.

  • Register a bean If a Class file is located in some location.

  • Register a bean If a property value is configured in some configuration file.

  • Register a bean If a System property is absent/present.

Suppose consider OracleDataDAO implemented with DataDAO which is used for getting connenction from Oracle database. Once the connection happens then data will be fetched from the database. So OracleDataDAO class's registration is required. Here the condition for Registering of a bean is If a property value i.e., DataBaseType is configured in some configuration file.

Please observe the below-given example code for OracleDataDAO.

OracleDataDAO.java
public class OracleDataDAO implements DataDAO
{
 	@Override
 	public List  getTableData() {
		//
 	}
}

Based on passing the "DbType" System property the connection will be created for fetching the data from Oracle Database. Use the command "java -jar myapp.jar -DbType=Oracle" to get a connection from Oracle.

The condition should be implemented as given below for the Oracle database. It will be implemented based on system DbType property.

Condition example in SpringBoot
public class OracleDatabaseTypeCondition implements Condition {
 
@Override
 public boolean matches(ConditionContext conditionContext, AnnotatedTypeMetadata metadata)
 {
 		String enabledDBName = System.getProperty("DbType");
		 return (enabledDBType != null && enabledDBType.equalsIgnoreCase("Oracle"));
 }
}

If the condition is the Type of loaded driver class of Oracle then the condition will be as given below.

Condition example of Class Path Checking
public class OracleDriverTypeCondition implements Condition
{
 @Override
 	public boolean matches(ConditionContext conditionContext,AnnotatedTypeMetadata metadata) {
 		try {
 			Class.forName("com.oracle.driver");
 			return true;
 		} catch (ClassNotFoundException e) {
 			return false;
 		}
 	}
}

If we run the application like java -jar myapp.jar -DbType=Oracle then the appropriate driver class will be registered and executed accordingly. The same way conditions will be implemented for different types of databases.

In the same way as the above-written code, we can write with an annotation which will be very useful for users.

Condition example in SpringBoot
public class DatabaseTypeCondition implements Condition {
 	@Override
 	public boolean matches(ConditionContext conditionContext,AnnotatedTypeMetadata metadata) {

	 Map<String, Object> attributes = metadata.getAnnotationAttributes(DatabaseType.class.getName());
	 String name = (String) attributes.get("value");
	 String enabledDBType = System.getProperty("dbType","Oracle");
 	 return (enabledDBType != null && type!= null && enabledDBType.equalsIgnoreCase(type));

	 }
}

Now we can use the @DatabaseType annotation on our bean definitions as follows:

@Configuration
@ComponentScan
public class AppConfig {
	@DatabaseType("Oracle")
	public DataDAO dataDAO(){
		return new OracleDataDAO();
	}
}

So here it will check the loaded driver class whether Oracle or not. If yes Spring will register the oracle driver class then appropriate DataDAO class will be used for fetching the data from the Oracle Database.

Auto Configuration Example

Generally, the Auto Configuration will try to find the classes which are available in the class path. Then Spring enables registration of classes by the Auto Configuration. Spring will use the annotations @ConditionalOnClass, @ConditionalOnMissingBean to register these classes.

Auto Configuration Example
@Configuration
@ConditionalOnClass({ DataSource.class, EmbeddedDatabaseType.class })
@EnableConfigurationProperties(DataSourceProperties.class)
@Import({ Registrar.class, DataSourcePoolMetadataProvidersConfiguration.class })
public class DataSourceAutoConfiguration {

}
Leave A Reply