This chapter covers
Although the Greek philosopher Heraclitus wasn’t well known as a software developer, he seemed to have a good handle on the subject. He has been quoted as saying, “The only constant is change.” That statement captures a foundational truth of software development.
The way we develop applications today is different than it was a year ago, 5 years ago, 10 years ago, and certainly 15 years ago, when an initial form of the Spring Framework was introduced in Rod Johnson’s book, Expert One-on-One J2EE Design and Development (Wrox, 2002, http://mng.bz/oVjy).
Back then, the most common types of applications developed were browser-based web applications, backed by relational databases. While that type of development is still relevant, and Spring is well equipped for those kinds of applications, we’re now also interested in developing applications composed of microservices destined for the cloud that persist data in a variety of databases. And a new interest in reactive programming aims to provide greater scalability and improved performance with non-blocking operations.
As software development evolved, the Spring Framework also changed to address modern development concerns, including microservices and reactive programming. Spring also set out to simplify its own development model by introducing Spring Boot.
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 chapter is your first step in a journey through modern application development with Spring.
I know you’re probably itching to start writing a Spring application, and I assure you that before this chapter ends, you’ll have developed a simple one. But first, let me set the stage with a few basic Spring concepts that will help you understand what makes Spring tick.
Any non-trivial application is composed of many components, each responsible for its own piece of the overall application functionality, coordinating with the other application elements to get the job done. When the application is run, those components somehow need to be created and introduced to each other.
At its core, Spring offers a container, often referred to as the Spring application context, that creates and manages application components. These components, or beans, are wired together inside the Spring application context to make a complete application, much like bricks, mortar, timber, nails, plumbing, and wiring are bound together to make a house.
The act of wiring beans together is based on a pattern known as dependency injection (DI). Rather than have components create and maintain the lifecycle of other beans that they depend on, a dependency-injected application relies on a separate entity (the container) to create and maintain all components and inject those into the beans that need them. This is done typically through constructor arguments or property accessor methods.
For example, suppose that among an application’s many components, there are two that you’ll address: an inventory service (for fetching inventory levels) and a product service (for providing basic product information). The product service depends on the inventory service to be able to provide a complete set of information about products. Figure 1.1 illustrates the relationships between these beans and the Spring application context.
On top of its core container, Spring and a full portfolio of related libraries offer a web framework, a variety of data persistence options, a security framework, integration with other systems, runtime monitoring, microservice support, a reactive programming model, and many other features necessary for modern application development.
Historically, the way you would guide Spring’s application context to wire beans together was with one or more XML files that described the components and their relationship to other components. For example, the following XML declares two beans, an InventoryService bean and a ProductService bean, and wires the InventoryService bean into ProductService via a constructor argument:
<bean id="inventoryService" class="com.example.InventoryService" /> <bean id="productService" class="com.example.ProductService" /> <constructor-arg ref="inventoryService" /> </bean>
In recent versions of Spring, however, a Java-based configuration is more common. The following Java-based configuration class is equivalent to the XML configuration:
@Configuration public class ServiceConfiguration { @Bean public InventoryService inventoryService() { return new InventoryService(); } @Bean public ProductService productService() { return new ProductService(inventoryService()); } }
The @Configuration annotation indicates to Spring that this is a configuration class that will provide beans to the Spring application context. The configuration’s class methods are annotated with @Bean, indicating that the objects they return should be added as beans in the application context (where, by default, their respective bean IDs will be the same as the names of the methods that define them).
Java-based configuration offers several benefits over XML-based configuration, including greater type safety and improved refactorability. Even so, explicit configuration with either Java or XML is only necessary if Spring is unable to automatically configure the components.
Automatic configuration has its roots in the Spring techniques known as autowiring and component scanning. With component scanning, Spring can automatically discover components from an application’s classpath and create them as beans in the Spring application context. With autowiring, Spring automatically injects the components with the other beans that they depend on.
More recently, with the introduction of Spring Boot, automatic configuration has gone well beyond component scanning and autowiring. Spring Boot is an extension of the Spring Framework that offers several productivity enhancements. The most well-known of these enhancements is autoconfiguration, where Spring Boot can make reasonable guesses of what components need to be configured and wired together, based on entries in the classpath, environment variables, and other factors.
I’d like to show you some example code that demonstrates autoconfiguration. But I can’t. You see, autoconfiguration is much like the wind. You can see the effects of it, but there’s no code that I can show you and say “Look! Here’s an example of autoconfiguration!” Stuff happens, components are enabled, and functionality is provided without writing code. It’s this lack of code that’s essential to autoconfiguration and what makes it so wonderful.
Spring Boot autoconfiguration has dramatically reduced the amount of explicit configuration (whether with XML or Java) required to build an application. In fact, by the time you finish the example in this chapter, you’ll have a working Spring application that has only a single line of Spring configuration code!
Spring Boot enhances Spring development so much that it’s hard to imagine developing Spring applications without it. For that reason, this book treats Spring and Spring Boot as if they were one and the same. We’ll use Spring Boot as much as possible, and explicit configuration only when necessary. And, because Spring XML configuration is the old-school way of working with Spring, we’ll focus primarily on Spring’s Java-based configuration.
But enough of this chitchat, yakety-yak, and flimflam. This book’s title includes the phrase in action, so let’s get moving, and you can start writing your first application with Spring.
Through the course of this book, you’ll create Taco Cloud, an online application for ordering the most wonderful food created by man—tacos. Of course, you’ll use Spring, Spring Boot, and a variety of related libraries and frameworks to achieve this goal.
You’ll find several options for initializing a Spring application. Although 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 writing application code. Therefore, you’re going to lean on the Spring Initializr to bootstrap your application.
The Spring Initializr is both a browser-based web application and a REST API, which can produce a skeleton Spring project structure that you can flesh out with whatever functionality you want. Several ways to use Spring Initializr follow:
Rather than spend several pages of this chapter talking about each one of these options, I’ve collected those details in the appendix. In this chapter, and throughout this book, I’ll show you how to create a new project using my favorite option: Spring Initializr support in the 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; we can still be friends. Hop over to the appendix and substitute the Initializr option that suits you best for the instructions in the following sections. But know that throughout this book, I may occasionally reference features specific to Spring Tool Suite, such as the Spring Boot Dashboard. If you’re not using Spring Tool Suite, you’ll need to adapt those instructions to fit your IDE.
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.2 shows the menu structure to look for.
Once you select Spring Starter Project, a new project wizard dialog (figure 1.3) appears. The first page in the wizard asks you for some general project information, such as the project name, description, and 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 1.3, and then click Next.
The next page in the wizard lets you select dependencies to add to your project (see figure 1.4). Notice that near the top of the dialog, you can select which version of Spring Boot you want to base your project on. This defaults to the most current version available. 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 at the top of the Available list. For the Taco Cloud application, you’ll start with the dependencies shown in figure 1.4.
At this point, you can click Finish to generate the project and add it to your workspace. But if you’re feeling slightly adventurous, click Next one more time to see the final page of the new starter project wizard, as shown in figure 1.5.
By default, the new project wizard makes a call 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 second page of the wizard. But if for some reason you’re hosting your own clone of Initializr (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 to your Initializr instance before clicking Finish.
After you click Finish, the project is downloaded from the Initializr and loaded into your workspace. Wait a few moments for it to load and build, and then you’ll be ready to start developing application functionality. But first, let’s take a look at what the Initializr gave you.
After the project loads in the IDE, expand it to see what it contains. Figure 1.6 shows the expanded Taco Cloud project 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 these items:
As the Taco Cloud application grows, you’ll fill in this barebones project structure with Java code, images, stylesheets, tests, and other collateral that will make your project more complete. But in the meantime, let’s dig a little deeper into a few of the items that Spring Initializr provided.
When you filled out the Initializr form, you specified that your project should be built with Maven. Therefore, the Spring Initializr gave you a pom.xml file already populated with the choices you made. The following listing shows the entire pom.xml file provided by the Initializr.
<?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> 1 <name>taco-cloud</name> <description>Taco Cloud Example</description> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.0.4.RELEASE</version> 2 <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> 3 <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> <dependency> <groupId>org.seleniumhq.selenium</groupId> <artifactId>selenium-java</artifactId> <scope>test</scope> </dependency> <dependency> <groupId>org.seleniumhq.selenium</groupId> <artifactId>htmlunit-driver</artifactId> <scope>test</scope> </dependency> </dependencies> <build> <plugins> <plugin> 4 <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </build> </project>
The first noteworthy item in the pom.xml file is the <packaging> element. You chose to build your application as an executable JAR file, as opposed to a WAR file. This is probably one of the most curious choices you’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 UI 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’re not a natural fit for most cloud platforms. Although some cloud platforms (such as Cloud Foundry) are capable of deploying and running WAR files, all Java cloud platforms are capable of running an executable JAR file. Therefore, the Spring Initializr defaults to JAR packaging unless you tell it to do otherwise.
If you intend to deploy your application to a traditional Java application server, then you’ll need to choose WAR packaging and include a web initializer class. We’ll look at how to build WAR files in more detail in chapter 2.
Next, take note of the <parent> element and, more specifically, its <version> child. This specifies that your project has spring-boot-starter-parent as its parent POM. Among other things, this parent POM provides dependency management for several libraries commonly used in Spring projects. For those libraries covered by the parent POM, you won’t have to specify a version, as it’s inherited from the parent. The version, 2.0.4.RELEASE, indicates that you’re using Spring Boot 2.0.4 and, thus, will inherit dependency management as defined by that version of Spring Boot.
While we’re on the subject of dependencies, note 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 you 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. You didn’t have to check a box for it to be included because the Spring Initializr assumes (hopefully, correctly) that you’ll be writing tests.
You may also notice that all three dependencies have the word starter in their artifact ID. Spring Boot starter dependencies are special in that they typically don’t have any library code themselves, but instead transitively pull in other libraries. These starter dependencies offer three primary benefits:
Finally, the build specification ends with the Spring Boot plugin. This plugin performs a few important functions:
Speaking of the bootstrap class, let’s open it up and take a closer look.
Because you’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. You’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 the following listing.
package tacos; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; @SpringBootApplication 1 public class TacoCloudApplication { public static void main(String[] args) { SpringApplication.run(TacoCloudApplication.class, args); 2 } }
Although there’s 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. 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:
The other important piece of TacoCloudApplication is the main() method. This is the method that will be run when the JAR file is executed. For the most part, this method is boilerplate code; every Spring Boot application you write will have a method similar or identical to this one (class name differences notwithstanding).
The main() method 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 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 autoconfigured. You’ll define several configuration classes throughout the course of this book, so stay tuned for details.
Testing is an important part of software development. Recognizing this, the Spring Initializr gives you a test class to get started. The following listing shows the baseline test class.
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) 1 @SpringBootTest 2 public class TacoCloudApplicationTests { @Test 3 public void contextLoads() { } }
There’s not much to be seen in TacoCloudApplicationTests: the one test method in the class is empty. Even so, this test class does perform an essential check to ensure that the Spring application context can be loaded successfully. If you make any changes that prevent the Spring application context from being created, this test fails, and you can react by fixing the problem.
Also notice the class annotated with @RunWith(SpringRunner.class). @RunWith is a JUnit annotation, providing 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, JUnit is given SpringRunner, a Spring-provided test runner that provides for the creation of a Spring application context that the test will run against.
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, and was introduced in Spring 4.3 to remove the association with a specific version of JUnit (for example, JUnit 4). And there’s no denying that the alias is easier to read and type.
@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. Over the course of this book, you’ll see @SpringBootTest several times, and we’ll uncover some of its power.
Finally, there’s the test method itself. Although @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 fails.
At this point, we’ve concluded our review of the code provided by the Spring Initializr. You’ve seen some of the boilerplate foundation that you can use to develop a Spring application, but you still haven’t written a single line of code. Now it’s time to fire up your IDE, dust off your keyboard, and add some custom code to the Taco Cloud application.
Because you’re just getting started, we’ll start off with a relatively small change to the Taco Cloud application, but one that will demonstrate a lot of Spring’s goodness. It seems appropriate that as you’re just starting, the first feature you’ll add to the Taco Cloud application is a homepage. As you add the homepage, you’ll create two code artifacts:
And because testing is important, you’ll also write a simple test class to test the homepage. But first things first ... let’s write that controller.
Spring comes with a powerful web framework known as Spring MVC. At the center of Spring MVC is the concept of a controller, a class that handles requests and responds with information of some sort. In the case of a browser-facing application, a controller responds by optionally populating model data and passing the request on to a view to produce HTML that’s returned to the browser.
You’re going to learn a lot about Spring MVC in chapter 2. But for now, you’ll write a simple controller class that handles requests for the root path (for example, /) and forwards those requests to the homepage view without populating any model data. The following listing shows the simple controller class.
package tacos; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.GetMapping; @Controller 1 public class HomeController { @GetMapping("/") 2 public String home() { return "home"; 3 } }
As you can see, this class is annotated with @Controller. On its own, @Controller doesn’t do much. Its primary purpose is to identify this class as a component for component scanning. Because HomeController is annotated with @Controller, Spring’s component scanning automatically discovers it and creates an instance of HomeController as a bean in the Spring application context.
In fact, a handful of other annotations (including @Component, @Service, and @Repository) serve a purpose similar to @Controller. You could have just as effectively annotated HomeController with any of those other annotations, and it would have still worked the same. The choice of @Controller is, however, more descriptive of this component’s role in the application.
The home() method is as simple as controller methods come. It’s annotated with @GetMapping to indicate that if an HTTP GET request is received for the root path /, then this method should handle that request. It does so by doing nothing more than returning a String value of home.
This value is interpreted as the logical name of a view. How that view is implemented depends on a few factors, but because Thymeleaf is in your classpath, you can define that template with Thymeleaf.
You may be wondering why you chose Thymeleaf for a template engine. Why not JSP? Why not FreeMarker? Why not one of several other options?
Put simply, I had to choose something, and I like Thymeleaf and generally prefer it over those other options. And even though JSP may seem like an obvious choice, there are some challenges to overcome when using JSP with Spring Boot. I didn’t want to go down that rabbit hole in chapter 1. Hang tight. We’ll look at other template options, including JSP, in chapter 2.
The template name is derived from the logical view name by prefixing it with /templates/ and postfixing it with .html. The resulting path for the template is /templates/home.html. Therefore, you’ll need to place the template in your project at /src/main/resources/templates/home.html. Let’s create that template now.
In the interest of keeping your homepage simple, it should do nothing more than welcome users to the site. The next listing shows the basic Thymeleaf template that defines the Taco Cloud homepage.
<!DOCTYPE html> <html xmlns="http://www.w3.org/1999/xhtml" xmlns:th="http://www.thymeleaf.org"> <head> <title>Taco Cloud</title> </head> <body> <h1>Welcome to...</h1> <img th:src="@{/images/TacoCloud.png}"/> </body> </html>
There’s not much to discuss with regard to this template. The only notable line of code is the one with the <img> tag to display the Taco Cloud logo. It uses a Thymeleaf th:src attribute and an @{...} expression to reference the image with a context-relative path. Aside from that, it’s not much more than a Hello World page.
But let’s talk about that image a bit more. I’ll leave it up to you to define a Taco Cloud logo that you like. You’ll need to make sure you place it at the right place within the project.
The image is referenced with the context-relative path /images/TacoCloud.png. As you’ll recall from our review of the project structure, static content such as images is kept in the /src/main/resources/static folder. That means that the Taco Cloud logo image must also reside within the project at /src/main/resources/static/images/TacoCloud.png.
Now that you’ve got a controller to handle requests for the homepage and a view template to render the homepage, you’re almost ready to fire up the application and see it in action. But first, let’s see how you can write a test against the controller.
Testing web applications can be tricky when making assertions against the content of an HTML page. Fortunately, Spring comes with some powerful test support that makes testing a web application easy.
For the purposes of the homepage, you’ll write a test that’s comparable in complexity to the homepage itself. Your test will perform an HTTP GET request for the root path / and expect a successful result where the view name is home and the resulting content contains the phrase “Welcome to...”. The following should do the trick.
package tacos; import static org.hamcrest.Matchers.containsString; import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.view; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest; import org.springframework.test.context.junit4.SpringRunner; import org.springframework.test.web.servlet.MockMvc; @RunWith(SpringRunner.class) @WebMvcTest(HomeController.class) 1 public class HomeControllerTest { @Autowired private MockMvc mockMvc; 2 @Test public void testHomePage() throws Exception { mockMvc.perform(get("/")) 3 .andExpect(status().isOk()) 4 .andExpect(view().name("home")) 5 .andExpect(content().string( 6 containsString("Welcome to..."))); } }
The first thing you might notice about this test is that it differs slightly from the TacoCloudApplicationTests class with regard to the annotations applied to it. Instead of @SpringBootTest markup, HomeControllerTest is annotated with @WebMvcTest. This is a special test annotation provided by Spring Boot that arranges for the test to run in the context of a Spring MVC application. More specifically, in this case, it arranges for HomeController to be registered in Spring MVC so that you can throw requests against it.
@WebMvcTest also sets up Spring support for testing Spring MVC. Although it could be made to start a server, mocking the mechanics of Spring MVC is sufficient for your purposes. The test class is injected with a MockMvc object for the test to drive the mockup.
The testHomePage() method defines the test you want to perform against the homepage. It starts with the MockMvc object to perform an HTTP GET request for / (the root path). From that request, it sets the following expectations:
If, after the MockMvc object performs the request, any of those expectations aren’t met, then the test fails. But your controller and view template are written to satisfy those expectations, so the test should pass with flying colors—or at least with some shade of green indicating a passing test.
The controller has been written, the view template created, and you have a passing test. It seems that you’ve implemented the homepage successfully. But even though the test passes, there’s something slightly more satisfying with seeing the results in a browser. After all, that’s how Taco Cloud customers are going to see it. Let’s build the application and run it.
Just as there are several ways to initialize a Spring application, there are several ways to run one. If you like, you can flip over to the appendix to read about some of the more common ways to run a Spring Boot application.
Because you chose to use Spring Tool Suite to initialize and work on the project, you have a handy feature called the Spring Boot Dashboard available to help you run your application inside the IDE. The Spring Boot Dashboard appears as a tab, typically near the bottom left of the IDE window. Figure 1.7 shows an annotated screenshot of the Spring Boot Dashboard.
I don’t want to spend much time going over everything the Spring Boot Dashboard does, although figure 1.7 covers some of the most useful details. The important thing to know right now is how to use it to run the Taco Cloud application. Make sure taco-cloud application is highlighted in the list of projects (it’s the only application shown in figure 1.7), and then click the start button (the left-most button with both a green triangle and a red square). The application should start right up.
As the application starts, you’ll see some Spring ASCII art fly by in the console, followed by some log entries describing the steps as the application starts. Before the logging stops, you’ll see a log entry saying Tomcat started on port(s): 8080 (http), which means that you’re ready to point your web browser at the homepage to see the fruits of your labor.
Wait a minute. Tomcat started? When did you deploy the application to Tomcat?
Spring Boot applications tend to bring everything they need with them and don’t need to be deployed to some application server. You never deployed your application to Tomcat ... Tomcat is a part of your application! (I’ll describe the details of how Tomcat became part of your application in section 1.3.6.)
Now that the application has started, point your web browser to http://localhost:8080 (or click the globe button in the Spring Boot Dashboard) and you should see something like figure 1.8. Your results may be different if you designed your own logo image. But it shouldn’t vary much from what you see in figure 1.8.
It may not be much to look at. But this isn’t exactly a book on graphic design. The humble appearance of the homepage is more than sufficient for now. And it provides you a solid start on getting to know Spring.
One thing I’ve glossed over up until now is DevTools. You selected it as a dependency when initializing your project. It appears as a dependency in the produced pom.xml file. And the Spring Boot Dashboard even shows that the project has DevTools enabled. But what is DevTools, and what does it do for you? Let’s take a quick survey of a couple of DevTools’ most useful features.
As its name suggests, DevTools provides Spring developers with some handy development-time tools. Among those are
It’s important to understand that DevTools isn’t an IDE plugin, nor does it require that you use a specific IDE. It works equally well in Spring Tool Suite, IntelliJ IDEA, and NetBeans. Furthermore, because it’s only intended for development purposes, it’s smart enough to disable itself when deploying in a production setting. (We’ll discuss how it does this when you get around to deploying your application in chapter 19.) For now, let’s focus on the most useful features of Spring Boot DevTools, starting with automatic application restart.
With DevTools as part of your project, you’ll be able to make changes to Java code and properties files in the project and see those changes applied after a brief moment. DevTools monitors for changes, and when it sees something has changed, it automatically restarts the application.
More precisely, when DevTools is in play, the application is loaded into two separate class loaders in the Java virtual machine (JVM). One class loader is loaded with your Java code, property files, and pretty much anything that’s in the src/main/ path of the project. These are items that are likely to change frequently. The other class loader is loaded with dependency libraries, which aren’t likely to change as often.
When a change is detected, DevTools reloads only the class loader containing your project code and restarts the Spring application context, but leaves the other class loader and the JVM intact. Although subtle, this strategy affords a small reduction in the time it takes to start the application.
The downside of this strategy is that changes to dependencies won’t be available in automatic restarts. That’s because the class loader containing dependency libraries isn’t automatically reloaded. This means that any time you add, change, or remove a dependency in your build specification, you’ll need to do a hard restart of the application for those changes to take effect.
By default, template options such as Thymeleaf and FreeMarker are configured to cache the results of template parsing so that templates don’t need to be reparsed with every request they serve. This is great in production, as it buys a bit of performance benefit.
Cached templates, however, are not so great at development time. Cached templates make it impossible to make changes to the templates while the application is running and see the results after refreshing the browser. Even if you’ve made changes, the cached template will still be in use until you restart the application.
DevTools addresses this issue by automatically disabling all template caching. Make as many changes as you want to your templates and know that you’re only a browser refresh away from seeing the results.
But if you’re like me, you don’t even want to be burdened with the effort of clicking the browser’s refresh button. It’d be much nicer if you could make the changes and witness the results in the browser immediately. Fortunately, DevTools has something special for those of us who are too lazy to click a refresh button.
When DevTools is in play, it automatically enables a LiveReload (http://livereload.com/) server along with your application. By itself, the LiveReload server isn’t very useful. But when coupled with a corresponding LiveReload browser plugin, it causes your browser to automatically refresh when changes are made to templates, images, stylesheets, JavaScript, and so on—in fact, almost anything that ends up being served to your browser.
LiveReload has browser plugins for Google Chrome, Safari, and Firefox browsers. (Sorry, Internet Explorer and Edge fans.) Visit http://livereload.com/extensions/ to find information on how to install LiveReload for your browser.
Although your project doesn’t yet use a database, that will change in chapter 3. If you choose to use the H2 database for development, DevTools will also automatically enable an H2 Console that you can access from your web browser. You only need to point your web browser to http://localhost:8080/h2-console to gain insight into the data your application is working with.
At this point, you’ve written a complete, albeit simple, Spring application. You’ll expand on it throughout the course of the book. But now is a good time to step back and review what you’ve accomplished and how Spring played a part.
Think back on how you got to this point. In short, these are the steps you’ve taken to build your Spring-based Taco Cloud application:
Seems pretty straightforward, doesn’t it? With the exception of the first step to bootstrap the project, each action you’ve taken has been keenly focused on achieving the goal of producing a homepage.
In fact, almost every line of code you’ve written is aimed toward that goal. Not counting Java import statements, I count only two lines of code in your controller class and no lines in the view template that are Spring-specific. And although the bulk of the test class utilizes Spring testing support, it seems a little less invasive in the context of a test.
That’s an important benefit of developing with Spring. You can focus on the code that meets the requirements of an application rather than on satisfying the demands of a framework. Although you’ll no doubt need to write some framework-specific code from time to time, it’ll usually be only a small fraction of your codebase. As I said before, Spring (with Spring Boot) can be considered the frameworkless framework.
How does this even work? What is Spring doing behind the scenes to make sure your application needs are met? To understand what Spring is doing, let’s start by looking at the build specification.
In the pom.xml file, you declared a dependency on the Web and Thymeleaf starters. These two dependencies transitively brought in a handful of other dependencies, including
It also brought Spring Boot’s autoconfiguration library along for the ride. When the application starts, Spring Boot autoconfiguration detects those libraries and automatically
In short, autoconfiguration does all the grunt work, leaving you to focus on writing code that implements your application functionality. That’s a pretty sweet arrangement, if you ask me!
Your Spring journey has just begun. The Taco Cloud application only touched on a small portion of what Spring has to offer. Before you take your next step, let’s survey the Spring landscape and see what landmarks you’ll encounter on your journey.
To get an idea of the Spring landscape, look no further than the enormous list of checkboxes on the full version of the Spring Initializr web form. It lists over 100 dependency choices, so I won’t try to list them all here or to provide a screenshot. But I encourage you to take a look. In the meantime, I’ll mention a few of the highlights.
As you might expect, the core Spring Framework is the foundation of everything else in the Spring universe. It provides the core container and dependency injection framework. But it also provides a few other essential features.
Among these is Spring MVC, Spring’s web framework. You’ve already seen how to use Spring MVC to write a controller class to handle web requests. What you’ve not yet seen, however, is that Spring MVC can also be used to create REST APIs that produce non-HTML output. We’re going to dig more into Spring MVC in chapter 2 and then take another look at how to use it to create REST APIs in chapter 6.
The core Spring Framework also offers some elemental data persistence support, specifically template-based JDBC support. You’ll see how to use JdbcTemplate in chapter 3.
In the most recent version of Spring (5.0.8), support was added for reactive-style programming, including a new reactive web framework called Spring WebFlux that borrows heavily from Spring MVC. You’ll look at Spring’s reactive programming model in part 3 and Spring WebFlux specifically in chapter 10.
We’ve already seen many of the benefits of Spring Boot, including starter dependencies and autoconfiguration. Be certain that we’ll use as much of Spring Boot as possible throughout this book and avoid any form of explicit configuration, unless it’s absolutely necessary. But in addition to starter dependencies and autoconfiguration, Spring Boot also offers a handful of other useful features:
What’s more, Spring Boot offers an alternative programming model based on Groovy scripts that’s called the Spring Boot CLI (command-line interface). With the Spring Boot CLI, you can write entire applications as a collection of Groovy scripts and run them from the command line. We won’t spend much time with the Spring Boot CLI, but we’ll touch on it on occasion when it fits our needs.
Spring Boot has become such an integral part of Spring development; I can’t imagine developing a Spring application without it. Consequently, this book takes a Spring Boot–centric view, and you might catch me using the word Spring when I’m referring to something that Spring Boot is doing.
Although the core Spring Framework comes with basic data persistence support, Spring Data provides something quite amazing: the ability to define your application’s data repositories as simple Java interfaces, using a naming convention when defining methods to drive how data is stored and retrieved.
What’s more, Spring Data is capable of working with a several different kinds of databases, including relational (JPA), document (Mongo), graph (Neo4j), and others. You’ll use Spring Data to help create repositories for the Taco Cloud application in chapter 3.
Application security has always been an important topic, and it seems to become more important every day. Fortunately, Spring has a robust security framework in Spring Security.
Spring Security addresses a broad range of application security needs, including authentication, authorization, and API security. Although the scope of Spring Security is too large to be properly covered in this book, we’ll touch on some of the most common use cases in chapters 4 and 12.
At some point, most applications will need to integrate with other applications or even with other components of the same application. Several patterns of application integration have emerged to address these needs. Spring Integration and Spring Batch provide the implementation of these patterns for Spring-based applications.
Spring Integration addresses real-time integration where data is processed as it’s made available. In contrast, Spring Batch addresses batched integration where data is allowed to collect for a time until some trigger (perhaps a time trigger) signals that it’s time for the batch of data to be processed. You’ll explore both Spring Batch and Spring Integration in chapter 9.
As I’m writing this, the application development world is entering a new era where we’ll no longer develop our applications as single deployment unit monoliths and will instead compose applications from several individual deployment units known as microservices.
Microservices are a hot topic, addressing several practical development and runtime concerns. In doing so, however, they bring to fore their own challenges. Those challenges are met head-on by Spring Cloud, a collection of projects for developing cloud-native applications with Spring.
Spring Cloud covers a lot of ground, and it’d be impossible to cover it all in this book. We’ll look at some of the most common components of Spring Cloud in chapters 13, 14, and 15. For a more complete discussion of Spring Cloud, I suggest taking a look at Spring Microservices in Action by John Carnell (Manning, 2017, www.manning.com/books/spring-microservices-in-action).