Over a million developers have joined DZone.
{{announcement.body}}
{{announcement.title}}

Under The Boot – Spring Boot

DZone's Guide to

Under The Boot – Spring Boot

How Spring boot is automatically creating right components for your app.

· Java Zone
Free Resource

Check out this 8-step guide to see how you can increase your productivity by skipping slow application redeploys and by implementing application profiling, as you code! Brought to you in partnership with ZeroTurnaround.

Remember 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.

Image title

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 provide entityManager)
  • EnableTransactionManagement (to provide transactionManager)

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 by DataSourceAutoConfiguration.NonEmbeddedConfiguration.dataSource())
  • entityManagerFactory (org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean—added by JpaBaseConfiguration.entityManagerFactory() (parent of HibernateJpaAutoConfiguration))
  • transactionManager (org.springframework.orm.jpa.JpaTransactionManager—added by JpaBaseConfiguration.transactionManager() (parent of HibernateJpaAutoConfiguration)

Dependencies are summarized in the diagram below:

Image title


A showcase project can be found here.

The Java Zone is brought to you in partnership with ZeroTurnaround. Check out this 8-step guide to see how you can increase your productivity by skipping slow application redeploys and by implementing application profiling, as you code!

Topics:
java ,spring boot

Opinions expressed by DZone contributors are their own.

The best of DZone straight to your inbox.

SEE AN EXAMPLE
Please provide a valid email address.

Thanks for subscribing!

Awesome! Check your inbox to verify your email so you can start receiving the latest in tech news and resources.
Subscribe

{{ parent.title || parent.header.title}}

{{ parent.tldr }}

{{ parent.urlSource.name }}