From Spring in Action, Fifth Edition By Craig Walls

Whether you’re developing a simple database-backed web application or constructing a modern application built around microservices, Spring is the framework that will help you achieve your goals. This article, adapted from chapter 1 of Spring in Action, Fifth Edition, is your first step in a journey through modern application development with Spring.


Save 37% on Spring in Action, Fifth EditionJust enter code fccwalls into the discount code box at checkout at manning.com.


Initializing a Spring application

Imagine that we’re going to create Taco Cloud, an online application for ordering the most wonderful food created by man: tacos. Of course, we’re going to use Spring, Spring Boot, and a variety of related libraries and frameworks to achieve this goal.

There are several options for initializing a Spring application. While I could walk you through the steps of manually creating a project directory structure and defining a build specification, that’s wasted time–time better spent actually writing application code. Therefore, we’re going to lean on the Spring Initializr to bootstrap our application.

The Spring Initializr is both a browser-based web application as well as a REST API that can produce a skeleton Spring project structure that you can flesh out with whatever functionality you want. There are several ways to use Spring Initializr, including the following:

  • The web application at http://start.spring.io

  • From the command line using the curl command

  • From the command line using the Spring Boot Command Line Interface

  • When creating a new project in Spring Tool Suite

  • When creating a new project in IntelliJ IDEA

  • When creating a new project in Netbeans

Rather than spend several pages of this article talking about each one of these options, I’m going to show how to initialize a new project using my favorite option, the Spring Initializr support in Spring Tool Suite. As its name suggests, Spring Tool Suite is a fantastic Spring development environment. But it also offers a handy Spring Boot Dashboard feature that (at least at the time I write this) isn’t available in any of the other IDE options.

If you’re not a Spring Tool Suite user, that’s fine and we can still be friends, you’ll just need to adapt these instructions to fit your IDE.

Initializing a Spring project in Spring Tool Suite

To get started with a new Spring project in Spring Tool Suite, go to the “File” menu and select “New” and then “Spring Starter Project”. Figure 1 shows the menu structure to look for.


Figure 1. Starting a new project with the Intiializr in Spring Tool Suite.


Once you select “Spring Starter Project” a new project wizard dialog will appear, as shown in figure 2. The first page in the wizard asks you for some general project information, such as the project name, description, and some other essential information. If you’re familiar with the contents of a Maven pom.xml file, you’ll recognize most of the fields as items that end up in a Maven build specification.

For the Taco Cloud application, fill in the dialog as shown in figure 2, then click “Next >”.


Figure 2. Specifying general project information.


The next page in the wizard offers you the chance to select dependencies to add to your project (see Figure 3). Near the top of the dialog, you’ll notice that you have a chance to select which version of Spring Boot you want to base your project on. This defaults to the most current version available and it’s generally a good idea to leave it as-is, unless you need to target a different version.

As for the dependencies themselves, you can either expand the various sections and seek out the desired dependencies manually, or search for them in the search box near the top. For the Taco Cloud application, we’re going to start with the dependencies shown in Figure 3.


Figure 3. Choosing starter dependencies.


At this point you can just click “Finish” to generate the project and add it to your workspace. But, if you’re feeling slightly adventurous, click “Next >” one more time.


Figure 4. Optionally specifying an alternate Initializr address.


By default, this new project wizard makes a call out to the Spring Initializr at http://start.spring.io to generate the project.

Generally, there’s no need to override this default, which is why you could have clicked “Finish” on the 2nd page of the wizard. But, if for some reason you’re hosting your own clone of Intializr (perhaps a local copy on your own machine or a customized clone running inside your company firewall), then you’ll want to change the “Base Url” field to point at your Initializr instance before clicking “Finish”.

After you click “Finish”, the project will be downloaded from the Initializr and loaded into your workspace. Wait a few moments to give it a chance to load and build, and then you’ll be ready to start developing the application functionality. But first, let’s take a look at what the Initializr gave us.

Examining the Spring project structure

After the project has been loaded in the IDE, expand it to see what it contains. Figure 5 shows the expanded Taco Cloud project in Spring Tool Suite.


Figure 5. The initial Spring project structure as shown in Spring Tool Suite.


You may recognize this as a typical Maven or Gradle project structure, where application source code is placed under src/main/java, test code is placed under src/test/java, and non-Java resources are placed under src/main/resources. Within that project structure, you’ll want to take note of the following items:

  • mvnw and mvnw.cmd : These are Maven wrapper scripts. You can use these to build your project even if you don’t have Maven installed on your machine.

  • pom.xml : This is the Maven build specification. We’ll look deeper into this in a moment.

  • TacoCloudApplication.java : This is the Spring Boot main class that bootstraps the project. We’ll take a closer look at this class in a moment.

  • application.properties : This file is initially empty, but offers a place where you can specify configuration properties.

  • static : This folder is where you can place any static content (images, stylesheets, Javascript, etc) that you want to be able to serve to the browser. It is initially empty.

  • templates : This folder is where you’ll place template files that will be used to render content to the browser. It’s initially empty, but we can add a Thymeleaf template to it later.

  • TacoCloudApplicationTests.java : This is a very simple test class that ensures that the Spring application context will load successfully. We’ll certainly add more tests to the mix as we develop the application.

As the Taco Cloud application grows, we’ll most certainly fill in this barebones project structure with Java code, images, stylesheets, tests, and other collateral that will make our project more complete. But in the meantime, let’s dig a little deeper into a few of the items that Spring Initializr provided to us.

Exploring the build specification

When we filled out the form at https://start.spring.io, we specified that our project should be built with Maven. Therefore, the Spring Initializr gave us a pom.xml file, already populated with the choices we made. Listing 1 shows the entire pom.xml file provided by the Initializr.

Listing 1 The initial Maven build specification.

 
 <?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/xsd/maven-4.0.0.xsd">
   <modelVersion>4.0.0</modelVersion>
  
   <groupId>sia</groupId>
   <artifactId>taco-cloud</artifactId>
   <version>0.0.1-SNAPSHOT</version>
   <packaging>jar</packaging>                
  
   <name>taco-cloud</name>
   <description>Taco Cloud Example</description>
  
   <parent>
     <groupId>org.springframework.boot</groupId>
     <artifactId>spring-boot-starter-parent</artifactId>
     <version>2.0.0.M3</version>                    
     <relativePath/> <!-- lookup parent from repository -->
   </parent>
  
   <properties>
     <project.build.sourceEncoding>
         UTF-8</project.build.sourceEncoding>
     <project.reporting.outputEncoding>
         UTF-8</project.reporting.outputEncoding>
     <java.version>1.8</java.version>
   </properties>
  
   <dependencies>
     <dependency>                                             
       <groupId>org.springframework.boot</groupId>
       <artifactId>spring-boot-starter-thymeleaf</artifactId>
     </dependency>
     <dependency>
       <groupId>org.springframework.boot</groupId>
       <artifactId>spring-boot-starter-web</artifactId>
     </dependency>
     <dependency>
       <groupId>org.springframework.boot</groupId>
       <artifactId>spring-boot-devtools</artifactId>
       <scope>runtime</scope>
     </dependency>
  
     <dependency>
       <groupId>org.springframework.boot</groupId>
       <artifactId>spring-boot-starter-test</artifactId>
       <scope>test</scope>
     </dependency>
   </dependencies>
  
   <build>
     <plugins>
       <plugin>                                               
         <groupId>org.springframework.boot</groupId>
         <artifactId>spring-boot-maven-plugin</artifactId>
       </plugin>
     </plugins>
   </build>
  
   <repositories>
     <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-milestones</id>
       <name>Spring Milestones</name>
       <url>https://repo.spring.io/milestone</url>
       <snapshots>
         <enabled>false</enabled>
       </snapshots>
     </pluginRepository>
   </pluginRepositories>
  
 </project>
 

JAR packaging

Spring Boot version

Starter dependencies

Spring Boot plugin

The first noteworthy item in the pom.xml file is the <packaging> element. We chose to build our application as an executable JAR file, as opposed to a WAR file. This is probably one of the most curious choices we’ll make, especially for a web application. After all, traditional Java web applications are packaged as WAR files, leaving JAR files the packaging of choice for libraries (and the occasional desktop user-interface application).

The choice of JAR packaging is a cloud-minded choice. Whereas WAR files are perfectly suitable for deploying to a traditional Java application server, they are not a natural fit for most cloud platforms. While some cloud platforms (such as CloudFoundry) are capable of deploying and running WAR files, all Java cloud platforms are capable of running an executable JAR file. Therefore, the Spring Initializr will default to JAR packaging unless you tell it to do otherwise.

If you’ll need to deploy your application to a traditional Java application server, then you’ll need to choose WAR packaging and include a web initializer class.

Next, take note of the <parent> element and, more specifically, its <version> child. This specifies that our project has spring-boot-starter-parent as its parent POM. Among other things, this parent POM will provide dependency management for several dependency libraries commonly used in Spring projects. For those libraries covered by the parent POM, we will not have to specify a version, as it will be inherited from the parent. The version, 2.0.0.RELEASE indicates that we’re using Spring Boot 2.0.0 and thus will inherit dependency management as defined by that version of Spring Boot.

While we’re on the subject of dependencies, you’ll see that there are three dependencies declared under the <dependencies> element. The first two should look somewhat familiar to you. They correspond directly to the “web” and “thymeleaf” dependencies that we selected before clicking the “Finish” button in the Spring Tool Suite new project wizard. The third dependency is one that provides a lot of helpful testing capabilities. We didn’t have to check a box for it to be included because the Spring Initializr will assume (hopefully correctly) that you will be writing tests.

You may also notice that all three dependencies have the word “starter” in their artifact ID. Spring Boot starter dependencies are kind of special in that they typically don’t have any library code themselves, but instead will transitively pull in other libraries. These starter dependencies offer three primary benefits:

Your build file will be significantly smaller and easier to manage because you won’t need to declare a dependency on every library you might need.

You are able to think of your dependencies in terms of which capabilities they provide, rather than in terms of library names. If you’re developing a web application, you add the web starter dependency, rather than a laundry list of individual libraries that enable you to write a web application.

You are freed from the burden of worry about library versions. You can trust that, for a given version of Spring Boot, the versions of the libraries brought in transitively will be compatible. You only need to worry about which version of Spring Boot you’re using.

Finally, the build specification ends with the Spring Boot plugin. This plugin performs a few important functions:

  • It provides a Maven goal that will enable you to run the application using Maven.

  • It ensures that all dependency libraries are included within the executable JAR file and available on the runtime classpath.

  • It produces a manifest file in the JAR file that causes the bootstrap class (TacoCloudApplication in our case) is the main class for the executable JAR.

Speaking of the bootstrap class, let’s open it up and take a closer look.

Bootstrapping the application

Since we’ll be running the application from an executable JAR, it’s important to have a main class that will be executed when that JAR file is run. We’ll also need at least a minimal amount of Spring configuration to bootstrap the application. That’s what you’ll find in the TacoCloudApplication class, shown in listing 2.

Listing 2 The Taco Cloud bootstrap class.

 
 package tacos;
  
 import org.springframework.boot.SpringApplication;
 import org.springframework.boot.autoconfigure.SpringBootApplication;
  
 @SpringBootApplication   
 public class TacoCloudApplication {
  
   public static void main(String[] args) {
     SpringApplication.run(TacoCloudApplication.class, args); 
   }
  
 }
 

This is a Spring Boot application

Run the application

Although there’s very little code in TacoCloudApplication, what’s there packs quite a punch. One of the most powerful lines of code is also one of the shortest lines of code. The @SpringBootApplication annotation clearly signifies that this is a Spring Boot application. But there’s more to @SpringBootApplication than meets the eye.

@SpringBootApplication is a composite application that combines three other annotations:

  • @SpringBootConfiguration – Designates this class as a configuration class. Although there’s not much configuration in the class at this time, we can add Java-based Spring Framework configuration to this class if we need to. This annotation is, in fact, a specialized form of the @Configuration annotation.

  • @EnableAutoConfiguration – Enables Spring Boot automatic configuration. For now just know that this annotation tells Spring Boot to automatically configure any components that it thinks we need.

  • @ComponentScan – Enables component scanning. This lets us declare other classes with annotations like @Component, @Controller, @Service, and others to have Spring automatically discover them and register them as components in the Spring application context.

The other important piece of TacoCloudApplication is the main() method. This is the method that will be run when the executable JAR file is run. For the most part, this method is boilerplate code; every Spring Boot application you write will have a method very similar or identical to this one (class name differences notwithstanding).

The main() calls a static run() method on the SpringApplication class, which performs the actual bootstrapping of the application, creating the Spring application context. The two parameters passed to the run() method are a configuration class and the command line arguments. Although it’s not necessary that the configuration class passed to run() be the same as the bootstrap class, this is the most convenient and typical choice.

Chances are you won’t ever need to change anything in the bootstrap class. For simple applications, you might find it convenient to configure one or two other components in the bootstrap class, but for most applications you’re better off creating a separate configuration class for anything that isn’t auto-configured.

Testing the application

Testing is a very important part of software development. Recognizing this, the Spring Initializr has given us a test class to get started. Listing 3 shows the baseline test class.

Listing 3 A baseline application test.

 
 package tacos;
  
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.springframework.boot.test.context.SpringBootTest;
 import org.springframework.test.context.junit4.SpringRunner;
  
 @RunWith(SpringRunner.class)    
 @SpringBootTest                 
 public class TacoCloudApplicationTests {
  
   @Test                         
   public void contextLoads() {
   }
  
 }
 

Use the Spring runner

This is a Spring Boot test

The test method

There’s not much to be seen in TacoCloudApplicationTests. Even the one test method in the class is empty. Despite this, this test class does perform an essential check to be sure that the Spring application context can be loaded successfully. If we make any changes that prevent the Spring application context from being created, this test will fail and we can react by trying to fix the problem.

The class annotated with @RunWith(SpringRunner.class). @RunWith is a JUnit annotation which provides a test runner that guides JUnit in running a test. Think of it as applying a plugin to JUnit to provide custom testing behavior. In this case, it is given SpringRunner, which is a Spring-provided test runner that provides for the creation of a Spring application context that the test will run against.

Note a test runner by any other name…

If you’re already familiar with writing Spring tests or are maybe looking at some existing Spring-based test classes, you may have seen a test runner named SpringJUnit4ClassRunner. SpringRunner is an alias for SpringJUnit4ClassRunner that was introduced in Spring 4.3 to remove the association with a specific version of JUnit (e.g., JUnit 4). And there’s no denying that it’s easier to read and type.

The @SpringBootTest tells JUnit to bootstrap the test with Spring Boot capabilities. For now, it’s enough to think of this as the test class equivalent of calling SpringApplication.run() in a main() method.

Finally, there’s the test method itself. While @RunWith(SpringRunner.class) and @SpringBootTest are tasked to load the Spring application context for the test, they won’t have anything to do if there aren’t any test methods. Even without any assertions or code of any kind, this empty test method will prompt the two annotations to do their job and load the Spring application context. If there are any problems in doing so, the test will fail.

At this point, we’ve concluded our review of the code provided by the Spring Initializr. We’ve seen some of the boilerplate foundation that we can develop a Spring application on, but we still haven’t written a single line of code for ourselves. The next step would be to fire up your IDE, dust off your keyboard, and add some custom code to the Taco Cloud application.


If you want to learn more about the book, check it out on liveBook here and see this slide deck.