Under The Boot – Spring Boot
How Spring boot is automatically creating right components for your app.
Join the DZone community and get the full member experience.
Join For FreeRemember the times when we had to register dispatchers, viewResolvers, etc. to make our spring application web app? Then there was @EnableWebMvc
annotation, and now even this is redundant.
These days the only thing you need to do is to add org.springframework.boot:spring-boot-starter-web
dependency to your project and everything else is done automagically.
The same goes for a database connection. Not that long ago the minimum DB-aware Spring-context configuration was:
- Register data source (
<jdbc:embedded-database id="dataSource" type="HSQL"/>
) - Register entity manager (through entity manager factory) (
<bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
) - Register transaction manager (
<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager" >
) - Rurn on annotation driven transaction boundaries (
<tx:annotation-driven transaction-manager="transactionManager" proxy-target-class="false"/>
)
Along the way we dropped XML configs in favor of configurations. Now, all you need to do is to add another dependency org.springframework.boot:spring-boot-starter-data-jpa
and some DB driver (like com.h2database:h2
) and—again—Spring creates everything behind the curtains.
I don't know about you, but I grow suspicious when that many things happen without my knowledge. After using Spring Boot for a while I needed to look under the hood to feel safe again—not that much under—just enough to get back to my comfort zone.
High Level View
The basic mechanism goes like this:
All magically appearing beans are registered with Spring configurations (@Configuration
).
But those are loaded only if specific conditions are met—namely:
- The required class is available on the classpath (new beans magically created when dependency added).
- The required bean was not created explicitly by a programmer.
So for example—to load WebMvcAutoConfiguration
when Servlet
, DispatcherServlet
, and WebMvcConfigurerAdapter
classes are on the classpath, then @ConditionalOnClass({ Servlet.class, DispatcherServlet.class, WebMvcConfigurerAdapter.class })
is used.
This configuration loads all web MVC defaults, but again, for most of them only if the specific bean doesn't yet exist.
So, for example, to check if defaultViewResolver()
should be created, @ConditionalOnMissingBean(InternalResourceViewResolver.class)
is used.
@Configuration
@ConditionalOnWebApplication
@ConditionalOnClass({ Servlet.class, DispatcherServlet.class,
WebMvcConfigurerAdapter.class })
@ConditionalOnMissingBean(WebMvcConfigurationSupport.class)
(...)
public class WebMvcAutoConfiguration {
(...)
@Bean
@ConditionalOnMissingBean(InternalResourceViewResolver.class)
public InternalResourceViewResolver defaultViewResolver() {
InternalResourceViewResolver resolver = new InternalResourceViewResolver();
resolver.setPrefix(this.prefix);
resolver.setSuffix(this.suffix);
return resolver;
}
(...)
}
Where Is It Triggered?
It all begins with @SpringBootApplication
, the one you annotate your main class with. If you check its source you'll find out @EnableAutoConfiguration
there and this is responsible for most of the magic.
@SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication application = new SpringApplication(Application.class);
application.run(args);
}
}
If you check spring-boot-autoconfigure.jar/META-INF/spring.factories
you'll find the org.springframework.boot.autoconfigure.EnableAutoConfiguration
property which specifies which auto configurations will be used to "guess" and create beans you require.
DB Magic Example
So let's figure out how the required components for DB access are created.
To do so let's not use org.springframework.boot:spring-boot-starter-data-jpa
dependency in our showcase, but start with org.springframework.boot:spring-boot-starter
and see what dependencies should be added to create a database-aware app and how required steps are automagically performed.
With the spring-boot-starter:1.2.6.RELEASE
dependency I got 22 beans registered by Spring in my app (18 Spring beans + 4 application specific beans). There is no dataSource
or transactionManager
amongst them.
I want to add a hibernate entity to the project so I will include the org.hibernate:hibernate-entitymanager
compile dependency.
Now JtaAutoConfiguration
with jta properties
beans were added as javax.transaction.Transaction
appeared on the classpath.
I was hoping for HibernateJpaAutoConfiguration
to catch on, but this one also requires:
LocalContainerEntityManagerFactoryBean
(to provideentityManager
)EnableTransactionManagement
(to providetransactionManager
)
Both can be found in org.springframework:spring-orm
, so let's add this dependency to the classpath.
Now Spring will try to load HibernateJpaAutoConfiguration
, but this one requires dataSource
bean (@Autowired
as a private field), and we are still missing it.
It's easy to figure out that dataSource
will be created by DataSourceAutoConfiguration
(found on list in spring.factories
).
It seems that all conditions are met here, but the DataSourceAutoConfiguration
class can't be classloaded yet as it uses org.apache.tomcat.jdbc.pool.DataSourceProxy
, so it depends on org.apache.tomcat:tomcat-jdbc
. Let's add it to the class path as well.
Running the app we can see that we're getting closer as this time hibernate.dialect
can't be determined. No surprise here, it couldn't have been determined by Spring as we hadn't added any DB-specific dependency. So let's include com.h2database:h2a
.
Everything seems to work now. 54 beans loaded by spring. Among them:
- dataSource (
org.apache.tomcat.jdbc.pool.DataSource
—added byDataSourceAutoConfiguration.NonEmbeddedConfiguration.dataSource()
) - entityManagerFactory (
org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean
—added byJpaBaseConfiguration.entityManagerFactory()
(parent ofHibernateJpaAutoConfiguration
)) - transactionManager (
org.springframework.orm.jpa.JpaTransactionManager
—added byJpaBaseConfiguration.transactionManager()
(parent ofHibernateJpaAutoConfiguration
)
Dependencies are summarized in the diagram below:
A showcase project can be found here.
Opinions expressed by DZone contributors are their own.
Comments