© The Author(s), under exclusive license to APress Media, LLC, part of Springer Nature 2023
K. S. P. Reddy, S. UpadhyayulaBeginning Spring Boot 3https://doi.org/10.1007/978-1-4842-8792-7_1

1. Introduction to Spring Boot

Siva Prasad Reddy Katamreddy1   and Sai Subramanyam Upadhyayula2
(1)
Hyderabad, India
(2)
Rotterdam, The Netherlands
 

The Spring Framework is a popular and widely used Java framework for building web and enterprise applications. Spring, at its core, is a dependency injection container that provides flexibility to configure beans in multiple ways, such as XML, Annotations, and JavaConfig. Over the years, the Spring Framework has grown exponentially by addressing the needs of modern business applications like security, support for NoSQL datastores, handling big data, batch processing, integration with other systems, and more. Along with its subprojects, Spring has become a viable platform for building enterprise applications.

The Spring Framework is very flexible and provides multiple ways of configuring application components. With rich features combined with various configuration options, configuring Spring applications becomes complex and error prone. The Spring team created Spring Boot to address configuration complexity through its powerful AutoConfiguration mechanism.

This chapter takes a quick look at the Spring Framework. You’ll develop a web application using Spring MVC and JPA the traditional way (without Spring Boot). Then you will look at the pain points of the conventional way and see how to develop the same application using Spring Boot.

Overview of the Spring Framework

If you are a Java developer, there is a good chance that you have heard about the Spring Framework and have used it in your projects. The Spring Framework was created primarily as a dependency injection container, but it is much more than that. Spring is famous for several reasons:
  • Spring’s dependency injection approach encourages writing testable code.

  • Easy-to-use and powerful database transaction management capabilities

  • Spring simplifies integration with other Java frameworks, like the JPA/Hibernate ORM and JooQ.

  • State-of-the-art Web MVC framework for building web applications

Along with the Spring Framework, many other Spring subprojects help build applications that address modern business needs:
  • Spring Data: Simplifies data access from relational and NoSQL datastores

  • Spring Batch: Provides a powerful batch-processing framework

  • Spring Security: Robust security framework to secure applications

  • Spring Cloud: Provides a set of tools for developers to implement common distributed system patterns like Service Discovery, Configuration Management, Circuit Breaker, and more

  • Spring Integration: An implementation of enterprise integration patterns to facilitate integration with other enterprise applications using lightweight messaging and declarative adapters

There are many other interesting projects addressing various other modern application development needs. For more information, take a look at https://spring.io/projects .

Spring Configuration Styles

Spring initially provided an XML-based approach for configuring beans. Later, Spring introduced XML-based DSLs, Annotations , and JavaConfig-based approaches for configuring beans. Listings 1-1 through 1-3 show each of those configuration styles.
<bean id="userService" class="com.apress.myapp.service.UserService">
    <property name="userDao" ref="userDao"/>
</bean>
<bean id="userDao" class="com.apress.myapp.dao.JdbcUserDao">
    <property name="dataSource" ref="dataSource"/>
</bean>
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
    <property name="driverClassName" value="com.mysql.jdbc.Driver"/>
    <property name="url" value="jdbc:mysql://localhost:3306/test"/>
    <property name="username" value="root"/>
    <property name="password" value="secret"/>
</bean>
<!-- DSL based configuration  -->
<beans>
    <jee:jndi-lookup id="entityManagerFactory" jndi-name="persistence/defaultPU"/>
</beans>
Listing 1-1

Example of an XML-Based Configuration

@Service
public class UserService
{
    private final UserDao userDao;
    public UserService(UserDao dao){
        this.userDao = dao;
    }
    ...
    ...
}
@Repository
public class JdbcUserDao
{
    private final DataSource dataSource;
    public JdbcUserDao(DataSource dataSource){
        this.dataSource = dataSource;
    }
    ...
    ...
}
Listing 1-2

Example of an Annotation-Based Configuration

@Configuration
public class AppConfig
{
    @Bean
    public UserService userService(UserDao dao){
        return new UserService(dao);
    }
    @Bean
    public UserDao userDao(DataSource dataSource){
        return new JdbcUserDao(dataSource);
    }
    @Bean
    public DataSource dataSource(){
        BasicDataSource dataSource = new BasicDataSource();
        dataSource.setDriverClassName("com.mysql.jdbc.Driver");
        dataSource.setUrl("jdbc:mysql://localhost:3306/test");
        dataSource.setUsername("root");
        dataSource.setPassword("secret");
        return dataSource;
    }
}
Listing 1-3

Example of a JavaConfig-Based Configuration

Spring provides multiple approaches for configuring application components. You can use JavaConfig- and Annotation-based configuration styles in the same application. That is a lot of flexibility, which is good and bad. People new to the Spring Framework may get confused about which approach to follow.

The Spring community suggests you follow the JavaConfig-based approach, as it gives you more flexibility. But there is no one-size-fits-all kind of solution. You have to choose the approach based on your own application needs.

Now that you’ve had a glimpse of how various styles of Spring Bean configurations look, you’ll take a quick look at the configuration of a typical SpringMVC and JPA/Hibernate-based web application.

Developing a Web Application Using SpringMVC and JPA

Before getting to know Spring Boot and learning about its features, let’s look at a typical Spring web application configuration and learn about the pain points. Then, you will see how Spring Boot addresses those problems.

The first thing to do is create a Maven project called springmvc-jpa-demo and configure all the dependencies required in the pom.xml file , as shown in Listing 1-4.
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns:="http://maven.apache.org/POM/4.0.0"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
                 http://maven.apache.org/maven-v4_0_0.xsd">
  <modelVersion>4.0.0</modelVersion>
  <groupId>com.apress</groupId>
  <artifactId>springmvc-jpa-demo</artifactId>
  <packaging>war</packaging>
  <version>1.0-SNAPSHOT</version>
  <name>springmvc-jpa-demo</name>
  <properties>
     <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
     <maven.compiler.source>17</maven.compiler.source>
     <maven.compiler.target>17</maven.compiler.target>
     <failOnMissingWebXml>false</failOnMissingWebXml>
  </properties>
  <build>
     <plugins>
        <plugin>
           <groupId>org.apache.maven.plugins</groupId>
           <artifactId>maven-war-plugin</artifactId>
           <version>3.3.2</version>
        </plugin>
        <plugin>
           <groupId>org.codehaus.cargo</groupId>
           <artifactId>cargo-maven3-plugin</artifactId>
           <version>1.9.13</version>
           <configuration>
              <container>
                 <containerId>tomcat10x</containerId>
                 <type>embedded</type>
              </container>
              <deployables>
                 <deployable>
                    <type>war</type>
                    <location>${project.build.directory}/${project.build.finalName}.war</location>
                    <properties>
                       <context>/</context>
                    </properties>
                 </deployable>
              </deployables>
           </configuration>
        </plugin>
     </plugins>
  </build>
  <dependencies>
     <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-webmvc</artifactId>
        <version>5.3.21</version>
     </dependency>
     <dependency>
        <groupId>org.springframework.data</groupId>
        <artifactId>spring-data-jpa</artifactId>
        <version>2.7.1</version>
     </dependency>
     <dependency>
        <groupId>org.slf4j</groupId>
        <artifactId>jcl-over-slf4j</artifactId>
        <version>1.7.36</version>
     </dependency>
     <dependency>
        <groupId>org.slf4j</groupId>
        <artifactId>slf4j-api</artifactId>
        <version>1.7.36</version>
     </dependency>
     <dependency>
        <groupId>org.slf4j</groupId>
        <artifactId>slf4j-reload4j</artifactId>
        <version>1.7.36</version>
     </dependency>
     <dependency>
        <groupId>org.apache.logging.log4j</groupId>
        <artifactId>log4j-core</artifactId>
        <version>2.17.2</version>
     </dependency>
     <dependency>
        <groupId>com.h2database</groupId>
        <artifactId>h2</artifactId>
        <version>2.1.214</version>
     </dependency>
     <dependency>
        <groupId>org.apache.commons</groupId>
        <artifactId>commons-dbcp2</artifactId>
        <version>2.9.0</version>
     </dependency>
     <dependency>
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-java</artifactId>
        <version>8.0.29</version>
     </dependency>
     <dependency>
        <groupId>org.hibernate</groupId>
        <artifactId>hibernate-entitymanager</artifactId>
        <version>5.6.10.Final</version>
     </dependency>
     <dependency>
        <groupId>javax.servlet</groupId>
        <artifactId>javax.servlet-api</artifactId>
        <version>3.1.0</version>
        <scope>provided</scope>
     </dependency>
     <dependency>
        <groupId>org.thymeleaf</groupId>
        <artifactId>thymeleaf-spring5</artifactId>
        <version>3.0.15.RELEASE</version>
     </dependency>
  </dependencies>
</project>
Listing 1-4

The pom.xml File

All of the Spring MVC, Spring Data JPA, JPA/Hibernate, Thymeleaf, and Log4j dependencies are configured in the Maven pom.xml file. Also, it defines the maven-war-plugin and cargo-maven-plugin to run an embedded Tomcat container to save you the manual configuration of the Tomcat server to run your application.

Configure the service/DAO layer beans using JavaConfig , as shown in Listing 1-5.
package com.apress.demo.config;
import java.util.Properties;
import javax.persistence.EntityManagerFactory;
import javax.sql.DataSource;
import org.apache.commons.dbcp2.BasicDataSource;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;
import org.springframework.context.support.PropertySourcesPlaceholderConfigurer;
import org.springframework.core.env.Environment;
import org.springframework.core.io.ClassPathResource;
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
import org.springframework.instrument.classloading.InstrumentationLoadTimeWeaver;
import org.springframework.jdbc.datasource.init.DataSourceInitializer;
import org.springframework.jdbc.datasource.init.ResourceDatabasePopulator;
import org.springframework.orm.hibernate5.HibernateExceptionTranslator;
import org.springframework.orm.jpa.JpaTransactionManager;
import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
import org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.annotation.EnableTransactionManagement;
@Configuration
@EnableTransactionManagement
@EnableJpaRepositories(basePackages="com.apress.demo.repositories")
@PropertySource(value = { "classpath:application.properties" })
public class AppConfig {
  @Autowired
  private Environment env;
  @Bean
  public static PropertySourcesPlaceholderConfigurer placeHolderConfigurer()
  {
     return new PropertySourcesPlaceholderConfigurer();
  }
  @Bean
  public PlatformTransactionManager transactionManager()
  {
     EntityManagerFactory factory = entityManagerFactory().getObject();
     return new JpaTransactionManager(factory);
  }
  @Bean
  public LocalContainerEntityManagerFactoryBean entityManagerFactory()
  {
     LocalContainerEntityManagerFactoryBean factory = new LocalContainerEntityManagerFactoryBean();
     HibernateJpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter();
     vendorAdapter.setShowSql(Boolean.TRUE);
     factory.setDataSource(dataSource());
     factory.setJpaVendorAdapter(vendorAdapter);
     factory.setPackagesToScan(env.getProperty("packages-to-scan"));
     Properties jpaProperties = new Properties();
     jpaProperties.put("hibernate.hbm2ddl.auto", env.getProperty("hibernate.hbm2ddl.auto"));
     factory.setJpaProperties(jpaProperties);
     factory.afterPropertiesSet();
     factory.setLoadTimeWeaver(new InstrumentationLoadTimeWeaver());
     return factory;
  }
  @Bean
  public HibernateExceptionTranslator hibernateExceptionTranslator()
  {
     return new HibernateExceptionTranslator();
  }
  @Bean
  public DataSource dataSource()
  {
     BasicDataSource dataSource = new BasicDataSource();
     dataSource.setDriverClassName(env.getProperty("jdbc.driverClassName"));
     dataSource.setUrl(env.getProperty("jdbc.url"));
     dataSource.setUsername(env.getProperty("jdbc.username"));
     dataSource.setPassword(env.getProperty("jdbc.password"));
     return dataSource;
  }
  @Bean
  public DataSourceInitializer dataSourceInitializer(DataSource dataSource)
  {
     DataSourceInitializer dataSourceInitializer = new DataSourceInitializer();
     dataSourceInitializer.setDataSource(dataSource);
     ResourceDatabasePopulator databasePopulator = new ResourceDatabasePopulator();
     databasePopulator.addScript(new ClassPathResource(env.getProperty("init-scripts")));
     dataSourceInitializer.setDatabasePopulator(databasePopulator);
     dataSourceInitializer.setEnabled(Boolean.parseBoolean(env.getProperty("init-db", "false")));
     return dataSourceInitializer;
  }
}
Listing 1-5

The com.apress.demo.config.AppConfig.java File

In the AppConfig.java configuration class , you do the following:

  • Mark it as a Spring Configuration class using the @Configuration annotation.

  • Enable annotation-based transaction management using @EnableTransactionManagement.

  • Configure @EnableJpaRepositories to indicate where to look for Spring Data JPA repositories.

  • Configure the PropertyPlaceHolder bean using the @PropertySource annotation and the PropertySourcesPlaceholderConfigurer bean definition, which loads properties from the application.properties file.

  • Define beans for DataSource, JPA EntityManagerFactory, and JpaTransactionManager.

  • Configure the DataSourceInitializer bean to initialize the database by executing the data.sql script on application start-up.

  1. 1.

    Now configure the property placeholder values in application.properties , as shown in Listing 1-6.

     
jdbc.driverClassName=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/test
jdbc.username=root
jdbc.password=admin
init-db=true
init-scripts=data.sql
hibernate.dialect=org.hibernate.dialect.MySQLDialect
hibernate.show_sql=true
hibernate.hbm2ddl.auto=update
packages-to-scan=com.apress.demo
Listing 1-6

The src/main/resources/application.properties File

  1. 2.

    Create a simple SQL script called data.sql to populate sample data into the USER table, as shown in Listing 1-7.

     
delete from user;
insert into user(id, name) values(1,'John');
insert into user(id, name) values(2,'Smith');
insert into user(id, name) values(3,'Siva');
Listing 1-7

The src/main/resources/data.sql File

  1. 3.

    Create the log4j.properties file with a basic configuration, as shown in Listing 1-8.

     
log4j.rootCategory=INFO, stdout
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%5p %t %c{2}:%L - %m%n
log4j.category.com.apress=DEBUG
log4j.category.org.springframework=INFO
Listing 1-8

The src/main/resources/log4j.properties File

  1. 4.

    Now configure the Spring MVC web layer beans such as ThymeleafViewResolver, static ResourceHandlers, and MessageSource for i18n, as shown in Listing 1-9.

     
package com.apress.demo.config;
import org.springframework.context.MessageSource;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.support.ReloadableResourceBundleMessageSource;
import org.springframework.web.servlet.config.annotation.DefaultServletHandlerConfigurer;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import org.thymeleaf.spring5.SpringTemplateEngine;
import org.thymeleaf.spring5.templateresolver.SpringResourceTemplateResolver;
import org.thymeleaf.spring5.view.ThymeleafViewResolver;
@Configuration
@ComponentScan(basePackages = {"com.apress.demo.web"})
@EnableWebMvc
public class WebMvcConfig implements WebMvcConfigurer {
   @Bean
   public SpringResourceTemplateResolver templateResolver() {
       SpringResourceTemplateResolver templateResolver = new SpringResourceTemplateResolver();
       templateResolver.setPrefix("/WEB-INF/views/");
       templateResolver.setSuffix(".html");
       templateResolver.setTemplateMode("HTML5");
       templateResolver.setCacheable(false);
       return templateResolver;
   }
   @Bean
   public SpringTemplateEngine templateEngine() {
       SpringTemplateEngine templateEngine = new SpringTemplateEngine();
       templateEngine.setTemplateResolver(templateResolver());
       return templateEngine;
   }
   @Bean
   public ThymeleafViewResolver viewResolver() {
       ThymeleafViewResolver thymeleafViewResolver = new ThymeleafViewResolver();
       thymeleafViewResolver.setTemplateEngine(templateEngine());
       thymeleafViewResolver.setCharacterEncoding("UTF-8");
       return thymeleafViewResolver;
   }
   @Override
   public void addResourceHandlers(ResourceHandlerRegistry registry) {
       registry.addResourceHandler("/resources/**").addResourceLocations("/resources/");
   }
   @Override
   public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) {
       configurer.enable();
   }
   @Bean(name = "messageSource")
   public MessageSource messageSource() {
       ReloadableResourceBundleMessageSource messageSource = new ReloadableResourceBundleMessageSource();
       messageSource.setBasename("classpath:messages");
       messageSource.setCacheSeconds(5);
       messageSource.setDefaultEncoding("UTF-8");
       return messageSource;
   }
}
Listing 1-9

The com.apress.demo.config.WebMvcConfig.java File

In the WebMvcConfig.java configuration class , you do the following:

  • Mark it as a Spring Configuration class using @Configuration annotation.

  • Enable an annotation-based Spring MVC configuration using @EnableWebMvc.

  • Configure ThymeleafViewResolver by registering the TemplateResolver, SpringTemplateEngine, and ThymeleafViewResolver beans.

  • Register the ResourceHandlers bean to indicate requests for static resources. The URI /resources/** will be served from the /resources/ directory.

  • Configure a MessageSource bean to load i18n messages from ResourceBundle messages_{country-code}.properties from the classpath.

  1. 5.

    Create the messages.properties file in the src/main/resources folder and add the following property:

     
app.title=SpringMVC JPA Demo (Without SpringBoot)
  1. 6.

    Next, you register the Spring MVC FrontController servlet DispatcherServlet.

     
Note

Prior to the Servlet 3.x specification, you had to register servlets and filters in web.xml. Since the Servlet 3.x specification, you can register servlets and filters programmatically using ServletContainerInitializer. Spring MVC provides a convenient class called AbstractAnnotationConfigDispatcherServletInitializer to register DispatcherServlet.

Listing 1-10 shows how to configure the SpringWebAppInitializer.java class .
package com.apress.demo.config;
import javax.servlet.Filter;
import org.springframework.orm.jpa.support.OpenEntityManagerInViewFilter;
import org.springframework.web.servlet.support.AbstractAnnotationConfigDispatcherServletInitializer;
public class SpringWebAppInitializer extends AbstractAnnotationConfigDispatcherServletInitializer
{
    @Override
    protected Class<?>[] getRootConfigClasses()
    {
        return new Class<?>[] { AppConfig.class};
    }
    @Override
    protected Class<?>[] getServletConfigClasses()
    {
        return new Class<?>[] { WebMvcConfig.class };
    }
    @Override
    protected String[] getServletMappings()
    {
        return new String[] { "/" };
    }
    @Override
    protected Filter[] getServletFilters()
    {
       return new Filter[]{ new OpenEntityManagerInViewFilter() };
    }
}
Listing 1-10

The com.apress.demo.config.SpringWebAppInitializer.java File

In the SpringWebAppInitializer.java configuration class, you do the following:
  • Configure AppConfig.class as RootConfirationClasses, which will become the parent ApplicationContext that contains bean definitions shared by all child (DispatcherServlet) contexts.

  • Configure WebMvcConfig.class as ServletConfigClasses, which is the child ApplicationContext that contains WebMvc bean definitions.

  • Configure / as ServletMapping, which means that all the requests will be handled by DispatcherServlet.

  • Register OpenEntityManagerInViewFilter as a servlet filter so that you can lazy-load the JPA entity lazy collections while rendering the view.

  1. 7.

    Create a JPA entity user and its Spring Data JPA Repository interface UserRepository. Create a JPA entity called User.java , as shown in Listing 1-11, and a Spring Data JPA repository called UserRepository.java , as shown in Listing 1-12.

     
package com.apress.demo.domain;
import jakarta.persistence.*;
@Entity
public class User
{
    @Id @GeneratedValue(strategy=GenerationType.AUTO)
    private Integer id;
    private String name;
    public User()
    {
    }
    public User(Integer id, String name)
    {
        this.id = id;
        this.name = name;
    }
    public Integer getId()
    {
        return id;
    }
    public void setId(Integer id)
    {
        this.id = id;
    }
    public String getName()
    {
        return name;
    }
    public void setName(String name)
    {
        this.name = name;
    }
}
Listing 1-11

The com.apress.demo.domain.User.java File

package com.apress.demo.repositories;
import org.springframework.data.jpa.repository.JpaRepository;
import com.apress.demo.domain.User;
public interface UserRepository extends JpaRepository<User, Integer>
{
}
Listing 1-12

The com.apress.demo.repositories.UserRepository.java File

If you don’t understand what JpaRepository is, don’t worry. You will learn more about Spring Data JPA in future chapters.
  1. 8.

    Create a SpringMVC controller to handle URL /, which renders a list of users. See Listing 1-13.

     
package com.apress.demo.web.controllers;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import com.apress.demo.repositories.UserRepository;
@Controller
public class HomeController
{
    @Autowired
    private UserRepository userRepo;
    @RequestMapping("/")
    public String home(Model model)
    {
        model.addAttribute("users", userRepo.findAll());
        return "index";
    }
}
Listing 1-13

The com.apress.demo.web.controllers.HomeController.java File

  1. 9.

    Create a Thymeleaf view called index.html in the /WEB-INF/views/ folder to render a list of users, as shown in Listing 1-14.

     
<!DOCTYPE html>
<html xmlns:="http://www.w3.org/1999/xhtml"
      xmlns:th="http://www.thymeleaf.org">
    <head>
        <meta charset="utf-8"/>
        <title>Home</title>
    </head>
    <body>
        <h2 th:text="#{app.title}">App Title</h2>
        <table>
            <thead>
                <tr>
                    <th>Id</th>
                    <th>Name</th>
                </tr>
            </thead>
            <tbody>
                <tr th:each="user : ${users}">
                    <td th:text="${user.id}">Id</td>
                    <td th:text="${user.name}">Name</td>
                </tr>
            </tbody>
        </table>
    </body>
</html>
Listing 1-14

The src/main/webapp/WEB-INF/views/index.html File

You are all set now to run the application. Run the command mvn cargo:run. This command will start an embedded Tomcat container. Now point your browser to http://localhost:8080/springmvcjpa-demo. If you do, you should see the list of user details in a table, as shown in Figure 1-1.

A window of a list of user details. It has a heading that reads, Spring M V C J P A Demo, without spring boot, and a list of three I D names.

Figure 1-1

Showing a list of users

Yay, you did it. But wait, isn’t this too much work to just show a list of user details pulled from a database table?

Let’s be honest and fair. All this configuration is not just for this one use case. This configuration becomes the basis for the rest of the application. Again, this is too much work to do if you want to get up and running quickly. Another problem is assuming that you want to develop another SpringMVC application with a similar technical stack. You could copy and paste the configuration and tweak it. Right?

Remember one thing: if you have to do the same thing repeatedly, you should find an automated way to do it.

Apart from writing the same configuration again and again, do you see any other problems here? Let’s take a look at the problems I see:
  • You must search all the compatible libraries for the Spring version and configure them.

  • Most of the time, you configure the DataSource, EntitymanagerFactory, TransactionManager, etc. beans the same way. Wouldn’t it be great if Spring could do it for you automatically?

  • Similarly, you configure the SpringMVC beans like ViewResolver and MessageSource the same way most of the time . If Spring can automatically do it for you, that would be awesome.

What if Spring is capable of configuring beans automatically? What if you can customize the automatic configuration using simple, customizable properties?

For example, instead of mapping the DispatcherServlet url-pattern to /, you want to map it to /app/. Instead of putting Thymeleaf views in the /WEB-INF/views folder, you want to place them in the /WEB-INF/templates/ folder.

So basically, you want Spring to do things automatically yet provide the flexibility to override the default configuration more simply. You are about to enter the world of Spring Boot, where your dreams can come true!

A Quick Taste of Spring Boot

Welcome to Spring Boot! Spring Boot will configure application components automatically for you but allows you to override the defaults if you want to.

Instead of explaining this in theory, I prefer to explain it by example. In this section, you’ll see how to implement the same application using Spring Boot.
  1. 1.

    Create a Maven-based Spring Boot project and configure the dependencies in the pom.xml file , as shown in Listing 1-15.

     
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns:="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
                 http://maven.apache.org/maven-v4_0_0.xsd">
   <modelVersion>4.0.0</modelVersion>
   <groupId>com.apress</groupId>
   <artifactId>hello-springboot</artifactId>
   <packaging>jar</packaging>
   <version>0.0.1-SNAPSHOT</version>
   <name>hello-springboot</name>
   <parent>
       <groupId>org.springframework.boot</groupId>
       <artifactId>spring-boot-starter-parent</artifactId>
       <version>3.0.0-SNAPSHOT</version>
   </parent>
   <properties>
       <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
       <java.version>17</java.version>
   </properties>
   <dependencies>
       <dependency>
           <groupId>org.springframework.boot</groupId>
           <artifactId>spring-boot-starter-test</artifactId>
           <scope>test</scope>
       </dependency>
       <dependency>
           <groupId>org.springframework.boot</groupId>
           <artifactId>spring-boot-starter-data-jpa</artifactId>
       </dependency>
       <dependency>
           <groupId>org.springframework.boot</groupId>
           <artifactId>spring-boot-starter-web</artifactId>
       </dependency>
       <dependency>
           <groupId>org.springframework.boot</groupId>
           <artifactId>spring-boot-starter-thymeleaf</artifactId>
       </dependency>
       <dependency>
           <groupId>org.springframework.boot</groupId>
           <artifactId>spring-boot-devtools</artifactId>
           <optional>true</optional>
       </dependency>
       <dependency>
           <groupId>mysql</groupId>
           <artifactId>mysql-connector-java</artifactId>
       </dependency>
       <dependency>
           <groupId>com.h2database</groupId>
           <artifactId>h2</artifactId>
       </dependency>
   </dependencies>
   <build>
       <plugins>
           <plugin>
               <groupId>org.springframework.boot</groupId>
               <artifactId>spring-boot-maven-plugin</artifactId>
           </plugin>
       </plugins>
   </build>
</project>
Listing 1-15

The pom.xml File

Wow, this pom.xml file suddenly became so small!

Note

Don’t worry if this configuration doesn’t make sense at this point in time. You have plenty more to learn in the coming chapters.

If you want to use any of the MILESTONE or SNAPSHOT versions of Spring Boot, you need to configure the following milestone/snapshot repositories in pom.xml:
<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>3.0.0--SNAPSHOT</version>
</parent>
<repositories>
    <repository>
        <id>spring-snapshots</id>
        <name>Spring Snapshots</name>
        <url>https://repo.spring.io/snapshot</url>
        <snapshots>
            <enabled>true</enabled>
        </snapshots>
    </repository>
    <repository>
        <id>spring-milestones</id>
        <name>Spring Milestones</name>
        <url>https://repo.spring.io/milestone</url>
        <snapshots>
            <enabled>false</enabled>
        </snapshots>
    </repository>
</repositories>
<pluginRepositories>
    <pluginRepository>
        <id>spring-snapshots</id>
        <name>Spring Snapshots</name>
        <url>https://repo.spring.io/snapshot</url>
        <snapshots>
            <enabled>true</enabled>
        </snapshots>
    </pluginRepository>
    <pluginRepository>
        <id>spring-milestones</id>
        <name>Spring Milestones</name>
        <url>https://repo.spring.io/milestone</url>
        <snapshots>
            <enabled>false</enabled>
        </snapshots>
    </pluginRepository>
</pluginRepositories>
  1. 2.

    Configure datasource/JPA properties in src/main/resources/application.properties, as shown in Listing 1-16.

     
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:3306/test
spring.datasource.username=root
spring.datasource.password=admin
spring.sql.init.mode=always
spring.jpa.hibernate.ddl-auto=update
spring.jpa.show-sql=true
Listing 1-16

The src/main/resources/application.properties File

Copy the same data.sql file into the src/main/resources folder.
  1. 3.

    Create a JPA Entity called User.java, a Spring Data JPA Repository Interface called UserRepository.java, and a controller called HomeController.java, as shown in the previous springmvc-jpa-demo application.

     
  2. 4.

    Create a Thymeleaf view to show the list of users. You can copy /WEB-INF/views/index.html, which you created in the springmvc-jpa-demo application, into the src/main/resources/templates folder of this new project.

     
  3. 5.

    Create a Spring Boot EntryPointclass Application.java file with the main method, as shown in Listing 1-17.

     
package com.apress.demo;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class Application
{
    public static void main(String[] args)
    {
        SpringApplication.run(Application.class, args);
    }
}
Listing 1-17

The com.apress.demo.Application.java File

Now run Application.java as a Java application and point your browser to http://localhost:8080/. You should see the list of users in a table format.

By now, you might be scratching your head, thinking, “What is going on?” The next section explains what just happened.

Easy Dependency Management

The first thing to note is the use of the dependencies named spring-boot-starter-*. Remember that I said, Most of the time, you use the same configuration.” So, when you add the springboot-starter-web dependency , it will, by default, pull all the commonly used libraries while developing Spring MVC applications, such as spring-webmvc, jackson-json, validation-api, and tomcat.

You added the spring-boot-starter-data-jpa dependency. This pulls all the spring-data-jpa dependencies and adds Hibernate libraries because most applications use Hibernate as a JPA implementation.

Autoconfiguration

Not only does the spring-boot-starter-web add all these libraries but it also configures the commonly registered beans like DispatcherServlet, ResourceHandlers, MessageSource, etc. with sensible defaults.

You also added spring-boot-starter-thymeleaf, which not only adds the Thymeleaf library dependencies but also configures the ThymeleafViewResolver beans automatically.

You haven’t defined any DataSource, EntityManagerFactory, or TransactionManager beans, but they are automatically created. How?

Suppose you have in-memory database drivers like H2 or HSQL in the classpath. In that case, Spring Boot will automatically create an in-memory data source and register the EntityManagerFactory and TransactionManager beans automatically with sensible defaults.

But you are using MySQL, so you need to provide MySQL connection details explicitly. You have configured those MySQL connection details in the application.properties file and Spring Boot creates a DataSource using those properties.

Embedded Servlet Container Support

The most important and surprising thing is that you created a simple Java class annotated with some magical annotation (@SpringApplication), which has a main() method. By running that main() method, you can run the application and access it at http://localhost:8080/. Where does the servlet container come from?

You added spring-boot-starter-web, which pulls spring-boot-starter-tomcat automatically. When you run the main() method, it starts Tomcat as an embedded container so that you don’t have to deploy your application on any externally installed Tomcat server. What if you want to use a Jetty server instead of Tomcat? You simply exclude spring-boot-starter-tomcat from spring-boot-starter-web and include spring-boot-starter-jetty. That’s it.

But this looks magical!. You may be thinking Spring Boot looks cool, and it's doing a lot of things for you. You still don’t understand how it works behind the scenes.

I can understand. Watching a magic show is fun, but the mystery is not so fun with software development. Don’t worry; we will be looking at each of these things and I will explain in detail what’s happening behind the scenes. I don’t want to overwhelm you by dumping everything on you in this first chapter.

Summary

This chapter was a quick overview of various Spring configuration styles. The goal was to show you the complexity of configuring Spring applications. Also, you had a quick look at Spring Boot by creating a simple web application.

The next chapter takes a more detailed look at Spring Boot and shows how you can create Spring Boot applications in different ways.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.22.27.45