Learning Spring Boot

4.5 (2 reviews total)
By Greg L. Turnquist
  • Instant online access to over 7,500+ books and videos
  • Constantly updated with 100+ new titles each month
  • Breadth and depth in over 1,000+ technologies
  1. Quick Start with Groovy

About this book

This practical, accessible guide helps you get up and running fast with Spring Boot. This book starts by crafting a Spring MVC application using the Spring stack on top of Apache Tomcat, with little configuration on from your end. You will also learn how to write both JUnit and Spock test cases. Then, you'll pull back the curtain and see how Spring Boot works by using Spring Messaging (JMS and AMQP) as well as creating custom metrics, custom information, and custom CLI commands aimed at production environments. In the last two chapters, you'll see how Spring Boot supports everyday situations we all deal with. You will learn how to create multiple configurations inside your app that can interact with different data stores.

By the end of the book, you'll have a good understanding of how Spring Boot works, how it manages low-level infrastructure, and how to start out production-grade apps with built-in support tools as well as custom ones.

Publication date:
November 2014
Publisher
Packt
Pages
252
ISBN
9781784393021

 

Chapter 1. Quick Start with Groovy

 

"Working with Spring Boot is like pair-programming with the Spring developers."

 
 --Josh Long @starbuxman

This chapter introduces Spring Boot using the deft programming language of Groovy. If you're not interested in Groovy, you can enjoy a similar high-speed experience with pure Java in the next chapter.

In this chapter, we will cover the following topics:

  • Creating a full-blown Spring MVC web app with just a few lines of code

  • Seeing how to install Spring Boot's simple CLI

  • Learning how to write automated tests with both JUnit and Spock

  • Bundling up the application as a runnable JAR file

  • Ramping up our app to use templates and jQuery

  • Adding production-ready support such as metrics, health, environment, and other things with a single line of code

 

Getting started


Spring Boot lets us rapidly create rock solid applications. As an example, look at the following source code written in Groovy in app.groovy:

@RestController
class App {
    @RequestMapping("/")
    def home() {
        "Hello, world!"
    }
}

Believe it or not, this small chunk of code is a complete, runnable web application with the details shown as follows:

  • The @RestController annotation asks Spring MVC to look for web routes. This annotation also indicates that every HTTP endpoint in this class will write its results directly into the HTTP response instead of using a view.

  • The @RequestMapping annotation maps the home() method to the / route. (By the way, it doesn't really matter what the method is named.)

  • In Groovy, the final statement is the return value, so, there's no need to type return.

  • Also, we don't have to tag either the class or the method as public, and we can drop the semicolons, which really trims away the cruft.

Let's launch this app using Spring Boot's spring tool, aka the Command Line Interface (CLI) tool as shown here, and see what it produces. (I promise we'll see how to install it later in this chapter.)

$ spring run app.groovy

The output for the preceding command will be as follows:

  .   ____          _            __ _ _
/\\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _' | \ \ \ \
\\/  ___)| |_)| | | | | || (_| |  ) ) ) )
  '  |____| .__|_| |_|_| |_\__, | / / / /
=========|_|==============|___/=/_/_/_/
:: Spring Boot ::        (v1.1.6.RELEASE)

2014-06-11 22:50:24.435 ... : Starting application on retina with PID 55927 (/...
2014-06-11 22:50:24.610 ... : Refreshing org.springframework.boot.context.embe...
2014-06-11 22:50:25.194 ... : Overriding bean definition for bean 'beanNameVie...
2014-06-11 22:50:26.027 ... : Server initialized with port: 8080
2014-06-11 22:50:26.249 ... : Starting service Tomcat
2014-06-11 22:50:26.249 ... : Starting Servlet Engine: Apache Tomcat/7.0.54
2014-06-11 22:50:26.343 ... : Unknown loader org.springframework.boot.cli.comp...
2014-06-11 22:50:26.349 ... : Initializing Spring embedded WebApplicationContext
2014-06-11 22:50:26.349 ... : Root WebApplicationContext: initialization compl...
2014-06-11 22:50:26.825 ... : Mapping servlet: 'dispatcherServlet' to [/]
2014-06-11 22:50:26.827 ... : Mapping filter: 'hiddenHttpMethodFilter' to: [/*]
2014-06-11 22:50:27.332 ... : Mapped URL path [/**/favicon.ico] onto handler o...
2014-06-11 22:50:27.406 ... : Mapped "{[/],methods=[],params=[],headers=[],con...
2014-06-11 22:50:27.408 ... : Mapped "{[/error],methods=[],params=[],headers=[...
2014-06-11 22:50:27.408 ... : Mapped "{[/error],methods=[],params=[],headers=[...
2014-06-11 22:50:27.416 ... : Adding welcome page: file:/Users/gturnquist/Drop...
2014-06-11 22:50:27.418 ... : Root mapping to handler of type [class org.sprin...
2014-06-11 22:50:27.429 ... : Mapped URL path [/**] onto handler of type [clas...
2014-06-11 22:50:27.429 ... : Mapped URL path [/webjars/**] onto handler of ty...
2014-06-11 22:50:27.968 ... : Registering beans for JMX exposure on startup
2014-06-11 22:50:27.993 ... : Tomcat started on port(s): 8080/http
2014-06-11 22:50:27.994 ... : Started application in 3.937 seconds (JVM runnin...

Note

The console output has been edited to better fit this book.

Visit http://localhost:8080 in a browser to see the following output:

So, what all just happened? Let's walk through each phase.

The spring tool parsed app.groovy and spotted the @RestController annotation. This tipped it off to add Spring MVC to the classpath using Groovy's @Grab annotation (spring also does this if it spots @Controller or @EnableWebMvc). It makes our app look like the following code:

//@Grab("spring-boot-starter-web")
//@Grab("groovy-templates")

@RestController
class App {
    @RequestMapping("/")
    def home() {
        "Hello, world!"
    }
}

Tip

Downloading the example code

You can download the example code files for all Packt books you have purchased from your account at http://www.packtpub.com. If you purchased this book elsewhere, you can visit http://www.packtpub.com/support and register to have the files e-mailed directly to you.

Our preceding code has been manipulated like this:

  • The @Grab annotation is part of Groovy Grape (http://groovy.codehaus.org/Grape), a tool that pulls down third-party libraries from Maven central

  • The spring-boot-starter-web package is a Spring Boot package that pulls in all the dependencies needed for a Spring MVC app

  • The groovy-templates package gives us the option to use Groovy's built-in template support (which we aren't using in this example, but is included nonetheless)

Tip

Why are the first lines commented out? It's because these lines aren't really added to the code we wrote. Spring Boot doesn't use code generation, but instead makes changes inside its embedded Groovy compiler. The comments are simply to clarify what we wrote versus what Spring Boot effectively configured for us.

For those already familiar with Groovy Grape, it's true that @Grab actually requires a group ID, an artifact ID, and a version. However, spring has a shortcut; if we use a library supported by Spring Boot, we only need to specify the artifact ID. The rest of the library's coordinates are supplied by spring and are based on the version of Spring Boot's CLI we have installed. See https://github.com/spring-projects/spring-boot/blob/v1.1.6.RELEASE/spring-boot-dependencies/pom.xml for a detailed listing of supported libraries.

After adding these extra libraries, spring inserted a few extra import statements, as shown in the following code:

//@Grab("spring-boot-starter-web")
//@Grab("groovy-templates")

//import org.springframework.web.bind.annotation.*
//import org.springframework.web.servlet.config.annotation.*
//import org.springframework.web.servlet.*
//import org.springframework.web.servlet.handler.*
//import org.springframework.http.*
//import org.springframework.ui.*

//static import org.springframework.boot.cli.template.GroovyTemplate.template

@RestController
class App {
    @RequestMapping("/")
    def home() {
        "Hello, world!"
    }
}

These particular import statements are for Spring MVC. By automatically supplying these critical import statements, we don't need to know where @RestController or @RequestMapping are located. We don't need a particular IDE to solve it for us either. Instead, we can focus on the app and not worry about such low-level intimate details of Spring MVC.

Finally, spring adds Spring Boot's @EnableAutoConfiguration annotation to the class and creates a static void main method to run our app, as shown in the following code:

//@Grab("spring-boot-starter-web")
//@Grab("groovy-templates")

//import org.springframework.web.bind.annotation.*
//import org.springframework.web.servlet.config.annotation.*
//import org.springframework.web.servlet.*
//import org.springframework.web.servlet.handler.*
//import org.springframework.http.*
//import org.springframework.ui.*

//static import org.springframework.boot.cli.template.GroovyTemplate.template

//@EnableAutoConfiguration
@RestController
class App {
    @RequestMapping("/")
    def home() {
        "Hello, world!"
    }

    //static void main(String[] args) {
    //    SpringApplication.run(App.class, args)
    //}
}

Let's break down this App class:

  • The @EnableAutoConfiguration annotation signals Spring Boot to start making opinionated decisions on adding various components to our app. For example, since Spring MVC was pulled in, many critical beans are created that include view resolvers, an embedded Tomcat servlet container, and a dispatcher servlet. These and other components are created automatically and added to the application context, powering up our app.

  • The SpringApplication.run() method is Spring Boot's API to start up our app and create an application context. Wrapping it in static void main means that we can run this app anywhere there is a JVM installed.

Tip

We can also run spring run -d app.groovy to get Spring Boot's auto-configuration report, unveiling the decisions Spring Boot made. For more details about this report, see Chapter 3, Debugging and Managing Your App.

In the console output displayed earlier, we not only see the embedded Apache Tomcat servlet container, but also details about Spring MVC being configured. Let's zero in on one line of that console output. The following line shows one Spring MVC route being configured:

2014-06-11 22:50:27.406 ... : Mapped "{[/],methods=[],params=[],headers=[],con...

We can see our route to /. Even though it's not visible in this book, running the code will show definite linkage to our home() method.

Let's pick another line from that console output to checkout Tomcat's settings. The embedded Tomcat container is configured to run on port 8080, shown as follows (we'll learn how to easily change this later on in the book):

2014-06-11 22:50:27.993 ... : Tomcat started on port(s): 8080/http

Have you built Spring MVC apps before? Perhaps you recognize some of these components. It doesn't really matter if you're not familiar with Spring MVC. Spring Boot fired up enough infrastructure to host our web app and allowed us to concentrate our coding efforts on functional features. In this case, the app simply prints a Hello greeting on the web page.

Throughout this book, we'll explore how Spring Boot configures components automatically while keeping us in the driver's seat of app development. Also, we'll discover how to override Boot's opinion when needed.

 

Installing Spring Boot's CLI


One handy way to install things is with the Groovy enVironment Manager (GVM) which is found at http://gvmtool.net. It's cross platform and lets you manage multiple versions of various tools from the Groovy community, including Spring Boot's CLI. Installing gvm is super easy with the following command:

$ curl -s get.gvmtool.net | bash

If you are on Windows, of course, you'll have to visit the website for more directions. Assuming we have gvm installed, this is all it takes to install the Spring Boot CLI:

$ gvm install springboot
$ spring --version
Spring CLI v1.1.6.RELEASE
$ gvm ls springboot

=========================================================================
Available Springboot Versions
=========================================================================
> * 1.1.6.RELEASE
...
=========================================================================
+ - local version
* - installed
> - currently in use
=========================================================================

With GVM, you can readily switch to other versions by typing gvm use springboot <other version>.

There is an alternative if you are using a Mac. One of the most popular package managers for OS X is Homebrew (http://brew.sh). Assuming you have already set up brew, you can install the spring tool by typing:

$ brew tap pivotal/tap
$ brew install springboot
$ spring --version
Spring CLI v1.1.6.RELEASE

Tip

pivotal/tap (https://github.com/pivotal/homebrew-tap) is a Homebrew extension point with many modules from Pivotal, including Spring Boot's CLI tool.

You can also download the bits directly using the following URLs, although one of the preceding solutions is recommended:

Let's check out Spring Boot's CLI commands! To get a listing of what commands are available, use the following argument:

$ spring --help

We get a listing that includes these commands and common options:

Command

Description

run [options] <files> [--] [args]

This runs a Spring Groovy script

test [options] <files> [--] [args]

This runs a Spring Groovy script test

grab

This downloads a Spring Groovy script's dependencies to ./repository

jar [options] <jar-name> <files>

This creates a self-contained executable JAR file from a Spring Groovy script

shell

This starts a nested shell

-d, --debug Verbose mode

This prints additional status information for the command you are running

The most commonly used commands are run, test, and jar. We already used run at the beginning of this chapter. In the next section, we'll explore how to write some tests and run them with the test command. Further on in this chapter, we'll see how to bundle up our code into a runnable JAR file with the jar command.

 

Testing with Spring Boot's CLI


So far, we've seen a tiny app power up using the popular Spring and Apache Tomcat web stack with little effort from our end. Spring Boot was able to detect that we wanted a Spring MVC app, and it put together the components we needed. However, in this day and age, no application is complete without coding some tests. Let's dig in a little more and see how to write some automated tests.

The spring test command kicks off Spring Boot; however, instead of magically adding a static void main method to run our app, it auto-configures test runners based on the code we supply. Let's first look at this example of a domain class and its related test case found inside Spring Boot's collection of test cases:

class Book {
    String author
    String title
}

class BookTests {
    @Test
    void testBooks() {
        Book book = new Book(author: "Tom Clancy",
                                    title: "Threat Vector")
        assertEquals("Tom Clancy", book.author)
    }
}

The Book class is a simple domain object with two fields. The BookTests class is a class with a single test method flagged by JUnit's @Test annotation.

Tip

This chunk of code is part of Spring Boot's official collection of automated tests at https://github.com/spring-projects/spring-boot/blob/master/spring-boot-cli/test-samples/book_and_tests.groovy. In fact, there is a huge collection of samples for various features offered by Spring Boot CLI in the test-samples folder.

To run the tests, copy the preceding code into book_and_tests.groovy and invoke the test command:

$ spring test book_and_tests.groovy
Time: 0.264

OK (1 test)

Our test case passed! However, no test checkout is complete without a test failure. Let's force it to fail by replacing assertEquals("Tom Clancy", book.author) with assertEquals("Tom Clancy", book.title):

$ spring test book_and_tests.groovy
.E
Time: 0.262
There was 1 failure:
1) testBooks(BookTests)
org.junit.ComparisonFailure: expected:<T[om Clancy]> but was:<T[hreat Vector]>
    at org.junit.Assert.assertEquals(Assert.java:115)
    at org.junit.Assert.assertEquals(Assert.java:144)
    at org.junit.Assert$assertEquals.callStatic(Unknown Source)
    ...
    at BookTests.testBooks(book_and_tests.groovy:10)
...
FAILURES!!!
Tests run: 1,  Failures: 1

It failed on a string match as expected. Looking down the call stack, we can see exactly where it failed: book_and_tests.groovy:10. We changed the actual to book.title while keeping the expected at Tom Clancy.

JUnit isn't the only test framework spring supports. Spock (https://code.google.com/p/spock) is a very popular testing framework in the Groovy community. The spring test command supports it as well. An example of the Spoke framework is as follows:

class HelloSpock extends Specification {
    def "length of Spock's and his friends' names"() {
        expect:
        name.size() == length

        where:
        name     | length
        "Spock"  | 5
        "Kirk"   | 4
        "Scotty" | 6
    }
}

This test takes advantage of Groovy's ability to create a method name. By wrapping the string with double quotes, "length of Spock's and his friends' names"() becomes a legal method name. This pays off during test failures by providing a comprehensible error message that is also directly tied to the code, as we'll see later.

This test example shows a test closure at the top (expect: name.size() == length) followed by a table of inputs. Spock will iterate over each entry in the table and run it through the expect clause as a separate test. This is convenient when we need to run a series of data inputs and their expected outputs through a single test scenario and want to avoid writing multiple method calls.

The spring tool spots this code as a test because HelloSpock extends Spock's Specification interface:

$ spring test spock.groovy
.
Time: 0.22

OK (1 test)

Again, if we muck up our test case by replacing 4 with 40 and 6 with 16, we can see why it failed and where:

$ spring test spock.groovy
.EE
Time: 0.294
There were 2 failures:
1) length of Spock's and his friends' names(HelloSpock)
Condition not satisfied:

name.size() == length
|    |      |  |
Kirk 4      |  40
            false

    at HelloSpock.length of Spock's and his friends' names(spock.groovy:4)
2) length of Spock's and his friends' names(HelloSpock)
Condition not satisfied:

name.size() == length
|    |      |  |
|    6      |  16
Scotty      false

    at HelloSpock.length of Spock's and his friends' names(spock.groovy:4)

FAILURES!!!
Tests run: 1,  Failures: 2

This easy-to-read assertion output is thanks to Groovy's power assertions (http://groovy-lang.org/docs/groovy-2.3.0/html/documentation/core-testing-guide.html#_power_assertions) and not restricted to Spock.

Tip

A common issue with running more than one set of inputs and outputs through a single scenario is if the testing framework halts after the first error. With Spock, it clearly runs all inputs and shows us multiple failures, allowing us to fix bugs faster.

It's also easy to run both at the same time. Spring Boot can mix and match testing styles with ease:

$ spring test *.groovy
..
Time: 0.288

OK (2 tests)

In both our JUnit and Spock test cases, we didn't have to add any @Grab statements to pull in the libraries nor did we need any import statements. The spring test command automatically adds them in for us so we can work on writing the tests.

Tip

Which test suite is better, JUnit or Spock? Personally, I have more experience with JUnit, but Spock provides powerful assertion operations, the ability to give readable test names, and a strong way to iterate over multiple sets of data. If I were using Groovy for everyday application development, I would probably migrate towards Spock.

While reducing the need for @Grab and import statements reduces the amount of code we need to manage, some IDEs might not be up to date with Spring Boot CLI support, and hence report errors.

 

Bundling and deploying a Spring Boot application


So far, we have created a web app that fits in a tweet! This is reminiscent of Rob Winch's popular tweet:

Tip

Since the time of Rob's famous tweet, the Spring Framework has come out with @RestController, an annotation that is basically @Controller plus @ResponseBody. Using this, the code in this tweet can be reduced down to @RestController class ThisWillActuallyRun { @RequestMapping("/") String home() { "Hello world!" } }.

Next, we wrote some super simple automated tests. A big step for any application is deploying it to production. The spring tool gives us the means with its jar command:

$ spring jar app.jar app.groovy

This isn't just any JAR file. It's an executable JAR file with all the required dependencies embedded inside it.

I invite you to look inside the JAR file by typing jar tvf app.jar. It's not printed here for space reasons, but it contains several key parts:

  • Compiled App.class based on app.groovy is included

  • All required libraries are found in the lib/ folder

  • Spring Boot adds a little extra code designed to load and run the nested JAR files

Tip

Java doesn't provide any standardized way to load nested JAR files. Many people have tried to fill this gap by creating "shaded" JARs by unpacking all the class files and repacking them directly into the enclosing JAR file. This makes it hard to spot the libraries, removes their encapsulation, and even has the potential to violate certain project's licensing agreements. Boot instead provides the means to bundle up third-party JARs inside an enclosing JAR file and properly load them at runtime. Read more at http://docs.spring.io/spring-boot/docs/1.1.6.RELEASE/reference/htmlsingle/#executable-jar.

With our handy-dandy runnable JAR assembled, there's nothing left to do but run it:

$ java -jar app.jar

  .   ____          _            __ _ _
/\\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _' | \ \ \ \
\\/  ___)| |_)| | | | | || (_| |  ) ) ) )
  '  |____| .__|_| |_|_| |_\__, | / / / /
=========|_|==============|___/=/_/_/_/
:: Spring Boot ::        (v1.1.6.RELEASE)

2014-06-11 22:55:54.807 ... : Starting PackagedSpringApplicationLauncher on re...
2014-06-11 22:55:55.033 ... : Refreshing org.springframework.boot.context.embe...
2014-06-11 22:55:55.621 ... : Overriding bean definition for bean 'beanNameVie...
2014-06-11 22:55:56.578 ... : Server initialized with port: 8080
...

What are the implications? We can easily take our runnable JAR file and deploy it anywhere there is a JVM:

  • If our production environment is on a separate, private network, we can put the JAR file on a flash drive and walk it out to the server room

  • If we have SSH access, we can upload it from our development workstation

  • If we are using some PaaS provider such as Cloud Foundry (public, private, or hybrid), we can push it by typing cf push <my app name> -p app.jar

  • We can stage it on our extranet FTP site for customers or other team members to grab a copy

  • And…just about any other option imaginable

Even though Oracle officially ended all public updates to Java 6 in February 2013, Spring Boot still supports it. Spring Boot leverages many parts of Spring Framework 4.0 (especially the @Conditional annotation), which requires a minimum of Java 6. Java 6 has shown a relatively healthy adoption, so the odds of finding a machine unable to run any apps built with Boot are minuscule. Don't worry if you are using Java 7 or 8; Spring Framework 4 is ready to make full use of this as well!

Spring Boot uses embeddable Tomcat, so there isn't a hard requirement for any type of container to be installed on the target machine. Non-web apps (we'll explore this later in the book) don't even require Apache Tomcat. The JAR file itself is the new container that allows us to stop thinking in terms of old fashioned servlet containers. Instead, we can think in terms of apps. All these factors add up to maximum flexibility in application deployment.

 

Adding support for templates


Okay, we've created a super simple application using Groovy and Spring Boot. We also bundled it up as a runnable JAR file that can be deployed anywhere we can find a Java 6 (or higher) JVM. However, this toy app we've built so far was hard coded with Hello, world! content. Real apps need views that can handle dynamic data, right? Let's make some tweaks and call it app_with_views.groovy, as shown in the following code:

@Grab("thymeleaf-spring4")
@Controller
class ViewBasedApp {

    def chapters = ["Quick Start With Groovy",
        "Quick Start With Java",
        "Debugging and Managing Your App",
        "Data Access with Spring Boot",
        "Securing Your App"]

    @RequestMapping("/")
    def home(@RequestParam(value="name", defaultValue="World") String n) {
        new ModelAndView("home")
              .addObject("name", n)
            .addObject("chapters", chapters)
    }
}

What did we just do? We can see the following listed here:

  • The @Grab("thymeleaf-spring4") annotation pulls in the Thymeleaf template engine, which causes Boot to auto-configure some more infrastructure. Boot supports several template engines, but we'll be using Thymeleaf throughout this book.

  • Replacing @RestController with @Controller indicates that the return value of route methods is a view and not raw content.

  • The @RequestParam annotation lets us grab the incoming name parameter and put it in the view's ModelAndView instance.

  • The ModelAndView class is a nice container that lets us specify the view name and provide data objects to whatever template engine we choose (Thymeleaf in this case).

  • We are also using a fixed list of chapter titles from this book as additional data for the page to render. This simulates content being fetched from a database.

Tip

While this book uses Thymeleaf, Spring MVC doesn't require a particular template engine in order to use its model and view classes.

We need to craft our home template. Spring Boot auto-configures settings for multiple engines. When it comes to Thymeleaf, it prefixes all view names with templates/ and appends .html at the end. (See http://docs.spring.io/spring-boot/docs/1.1.6.RELEASE/reference/htmlsingle/#boot-features-spring-mvc-template-engines for more information.) To do so, we first need to create the templates directory adjacent to our code. Otherwise, Spring Boot CLI won't be able to find our template. Next, let's create templates/home.html, as shown in the following code:

<html>
    <head>
        <title>Learning Spring Boot - Chapter 1</title>
    </head>
    <body>
        <p th:text="'Hello, ' + ${name}"></p>
        <ol>
            <li th:each="chapter : ${chapters}" th:text="${chapter}"></li>
        </ol>
    </body>
</html>

Let's break down this template:

  • Thymeleaf is HTML compliant, meaning the templates are visible inside a browser without breaking anything (compared to things like JSPs in certain situations). Its engine plugs in via the th namespace, using that as the way to introduce expressions, access model objects, and so on.

  • The th:text="'Hello, ' + ${name}" attribute embedded inside the <p> element configures the text value of this element. In this case, it concatenates Hello with the name attribute that was supplied by the server.

  • This template also shows a numbered list of chapter titles from this book, using Thymeleaf's th:each iterator. Thymeleaf creates one <li> tag for each chapter supplied in ModelAndView and proceeds to set the text value of each line item with that particular row's chapter name.

Let's launch this template-based version of our app:

$ spring run app_with_views.groovy

If we navigate to the same http://localhost:8080 as before, we'll see the familiar Hello, world!, now accompanied by the listing of chapters. However, if we go to http://localhost:8080?name=Alice, we'll instead see Hello, Alice, as shown in the following screenshot:

Tip

Thymeleaf has a DOM-based parsing engine. Everything is handled by attributes in the th namespace. This means we can open up a Thymeleaf template with any browser with no problem because it's 100 percent valid HTML. Even though it's the chosen view technology for this book, diving into all of its intricacies would take up too much room. For more details, see http://www.thymeleaf.org.

 

Modernizing our app with JavaScript


We just saw that, with a single @Grab statement, Spring Boot automatically configured the Thymeleaf template engine and some specialized view resolvers. We took advantage of Spring MVC's ability to pass attributes to the template through ModelAndView. Instead of figuring out the details of view resolvers, we instead channeled our efforts into building a handy template to render data fetched from the server. We didn't have to dig through reference docs, Google, and Stack Overflow to figure out how to configure and integrate Spring MVC with Thymeleaf. We let Spring Boot do the heavy lifting.

But that's not enough, right? Any real application is going to also have some JavaScript. Love it or hate it, JavaScript is the engine for frontend web development. See how the following code lets us make things more modern by creating modern.groovy:

@Grab("org.webjars:jquery:2.1.1")
@Grab("thymeleaf-spring4")
@Controller
class ModernApp {

    def chapters = ["Quick Start With Groovy",
        "Quick Start With Java",
        "Debugging and Managing Your App",
        "Data Access with Spring Boot",
        "Securing Your App"]

    @RequestMapping("/")
    def home(@RequestParam(value="name", defaultValue="World") String n) {
        new ModelAndView("modern")
            .addObject("name", n)
            .addObject("chapters", chapters)
    }
}

A single @Grab statement pulls in jQuery 2.1.1. The rest of our server-side Groovy code is the same as before.

There are multiple ways to use JavaScript libraries. For Java developers, it's especially convenient to use the WebJars project (http://webjars.org), where lots of handy JavaScript libraries are wrapped up with Maven coordinates. Every library is found on the /webjars/<library>/<version>/<module> path. To top it off, Spring Boot comes with prebuilt support. Perhaps you noticed this buried in earlier console outputs:

...
2014-05-20 08:33:09.062  ... : Mapped URL path [/webjars/**] onto handler of [...
...

With jQuery added to our application, we can amp up our template (templates/modern.html) like this:

<html>
    <head>
        <title>Learning Spring Boot - Chapter 1</title>
        <script src="webjars/jquery/2.1.1/jquery.min.js"></script>
        <script>
            $(document).ready(function() {
                $('p').animate({
                    fontSize: '48px',
                }, "slow");
            });
        </script>
    </head>
    <body>
        <p th:text="'Hello, ' + ${name}"></p>
        <ol>
            <li th:each="chapter : ${chapters}" th:text="${chapter}"></li>
        </ol>
    </body>
</html>

What's different between this template and the previous one?

It has a couple extra <script> tags in the head section:

  • The first one loads jQuery from /webjars/jquery/2.1.1/jquery.min.js (implying that we can also grab jquery.js if we want to debug jQuery)

  • The second script looks for the <p> element containing our Hello, world! message and then performs an animation that increases the font size to 48 pixels after the DOM is fully loaded into the browser

If we run spring run modern.groovy and visit http://localhost:8080, then we can see this simple but stylish animation (which naturally doesn't render as well in a printed book). It shows us that all of jQuery is available for us to work with on our application.

Using Bower instead of WebJars

WebJars isn't the only option when it comes to adding JavaScript to our app. More sophisticated UI developers might use Bower (http://bower.io), a popular JavaScript library management tool. WebJars are useful for Java developers, but not every library has been bundled as a WebJar. There is also a huge community of frontend developers more familiar with Bower and NodeJS that will probably prefer using their standard tool chain to do their jobs.

We'll see how to plug that into our app. First, it's important to know some basic options. Spring Boot supports serving up static web resources from the following paths:

  • /META-INF/resources/

  • /resources/

  • /static/

  • /public/

To craft a Bower-based app with Spring Boot, we first need to craft a .bowerrc file in the same folder we plan to create our Spring Boot CLI application. Let's pick public/ as the folder of choice for JavaScript modules and put it in this file, as shown in the following code:

{
    "directory": "public/"
}

Tip

Do I have to use public? No. Again, you can pick any of the folders listed previously and Spring Boot will serve up the code. It's a matter of taste and semantics.

Our first step towards a Bower-based app is to define our project by answering a series of questions (this only has to be done once):

$ bower init
[?] name: app_with_bower
[?] version: 0.1.0
[?] description: Learning Spring Boot - bower sample
[?] main file:
[?] what types of modules does this package expose? amd
[?] keywords:
[?] authors: Greg Turnquist <[email protected]>
[?] license: ASL
[?] homepage: http://blog.greglturnquist.com/category/learning-spring-boot
[?] set currently installed components as dependencies? No
[?] add commonly ignored files to ignore list? Yes
[?] would you like to mark this package as private which prevents it from being accidentally published to the registry? Yes
...
[?] Looks good? Yes

Now that we have set our project, let's do something simple such as install jQuery with the following command:

$ bower install jquery --save
bower jquery#*                  cached git://github.com/jquery/jquery.git#2.1.1
bower jquery#*                validate 2.1.1 against git://github.com/jquery/jquery.git#*

These two commands will have created the following bower.json file:

{
  "name": "app_with_bower",
  "version": "0.1.0",
  "authors": [
    "Greg Turnquist <[email protected]>"
  ],
  "description": "Learning Spring Boot - bower sample",
  "license": "ASL",
  "homepage": "http://blog.greglturnquist.com/category/learning-spring-boot",
  "private": true,
  "ignore": [
    "**/.*",
    "node_modules",
    "bower_components",
    "public/",
    "test",
    "tests"
  ],
  "dependencies": {
    "jquery": "~2.1.1"
  }
}

It will also have installed jQuery 2.1.1 into our app with the following directory structure:

public
└── jquery
    ├── MIT-LICENSE.txt
    ├── bower.json
    └── dist
        ├── jquery.js
        └── jquery.min.js

Tip

We must include --save (two dashes) whenever we install a module. This ensures that our bower.json file is updated at the same time, allowing us to rebuild things if needed.

The altered version of our app with WebJars removed should now look like this:

@Grab("thymeleaf-spring4")
@Controller
class ModernApp {

    def chapters = ["Quick Start With Groovy",
        "Quick Start With Java",
        "Debugging and Managing Your App",
        "Data Access with Spring Boot",
        "Securing Your App"]

    @RequestMapping("/")
    def home(@RequestParam(value="name", defaultValue="World") String n) {
        new ModelAndView("modern_with_bower")
            .addObject("name", n)
            .addObject("chapters", chapters)
    }
}

The view name has been changed to modern_with_bower, so it doesn't collide with the previous template if found in the same folder.

This version of the template, templates/modern_with_bower.html, should look like this:

<html>
    <head>
        <title>Learning Spring Boot - Chapter 1</title>
        <script src="jquery/dist/jquery.min.js"></script>
        <script>
            $(document).ready(function() {
                $('p').animate({
                    fontSize: '48px',
                }, "slow");
            });
        </script>
    </head>
    <body>
        <p th:text="'Hello, ' + ${name}"></p>
        <ol>
            <li th:each="chapter : ${chapters}" th:text="${chapter}"></li>
        </ol>
    </body>
</html>

The path to jquery is now jquery/dist/jquery.min.js. The rest is the same as the WebJars example. We just launch the app with spring run modern_with_bower.groovy and navigate to http://localhost:8080. (Might need to refresh the page to ensure loading of the latest HTML.) The animation should work just the same.

The options shown in this section can quickly give us a taste of how easy it is to use popular JavaScript tools with Spring Boot. We don't have to fiddle with messy tool chains to achieve a smooth integration. Instead, we can use them the way they are meant to be used.

What about an app that is all frontend with no backend?

Perhaps we're building an app that gets all its data from a remote backend. In this age of RESTful backends, it's not uncommon to build a single page frontend that is fed data updates via AJAX.

Spring Boot's Groovy support provides the perfect and arguably smallest way to get started. We do so by creating pure_javascript.groovy, as shown in the following code:

@Controller
class JsApp { }

That doesn't look like much, but it accomplishes a lot. Let's see what this tiny fragment of code actually does for us:

  • The @Controller annotation, like @RestController, causes Spring Boot to auto-configure Spring MVC.

  • Spring Boot, as we've seen throughout this chapter, will launch an embedded Apache Tomcat server.

  • Spring Boot will serve up static content from resources, static, and public. Since there are no Spring MVC routes in this tiny fragment of code, things will fall to resource resolution.

Next, we can create a static/index.html page as follows:

<html>
    Greetings from pure HTML which can, in turn, load JavaScript!
</html>

Run spring run pure_javascript.groovy and navigate to http://localhost:8080. We will see the preceding plain text shown in our browser as expected. There is nothing here but pure HTML being served up by our embedded Apache Tomcat server. This is arguably the lightest way to serve up static content. Use spring jar, as we saw earlier in this chapter, and it's possible to easily bundle up our client-side app to be installed anywhere.

Spring Boot's support for static HTML, JavaScript, and CSS opens the door to many options. We can add WebJar annotations to JsApp or use Bower to introduce third-party JavaScript libraries in addition to any custom client-side code. We might just manually download the JavaScript and CSS. No matter what option we choose, Spring Boot CLI certainly provides a super simple way to add rich-client power for app development. To top it off, RESTful backends that are decoupled from the frontend can have different iteration cycles as well as different development teams.

Tip

You might need to configure CORS (http://spring.io/understanding/CORS) to properly handle making remote calls that don't go back to the original server.

 

Adding production-ready support features


So far, we have created a Spring MVC app with minimal code. We added views and JavaScript. We are on the verge of a production release.

Before deploying our rapidly built and modernized web application, we might want to think about potential issues that might arise in production:

  • What do we do when the system administrator wants to configure his monitoring software to ping our app to see if it's up?

  • What happens when our manager wants to know the metrics of people hitting our app?

  • What are we going to do when the Ops center supervisor calls us at 2:00 a.m. and we have to figure out what went wrong?

The last feature we are going to introduce in this chapter is Spring Boot's Actuator module and CRaSH remote shell support (http://www.crashub.org). These two modules provide some super slick, Ops-oriented features that are incredibly valuable in a production environment.

We first need to update our previous code (we'll call it ops.groovy), as shown in the following code:

@Grab("spring-boot-actuator")
@Grab("spring-boot-starter-remote-shell")
@Grab("org.webjars:jquery:2.1.1")
@Grab("thymeleaf-spring4")
@Controller
class OpsReadyApp {
    @RequestMapping("/")
    def home(@RequestParam(value="name", defaultValue="World") String n) {
        new ModelAndView("modern")
            .addObject("name", n)
    }
}

This app is exactly like the WebJars example with two key differences: it adds @Grab("spring-boot-actuator") and @Grab("spring-boot-starter-remote-shell").

When you run this version of our app, the same business functionality is available that we saw earlier, but there are additional HTTP endpoints available:

Actuator endpoint

Description

/autoconfig

This reports what Spring Boot did and didn't auto-configure and why

/beans

This reports all the beans configured in the application context (including ours as well as the ones auto-configured by Boot)

/configprops

This exposes all configuration properties

/dump

This creates a thread dump report

/env

This reports on the current system environment

/health

This is a simple endpoint to check life of the app

/info

This serves up custom content from the app

/metrics

This shows counters and gauges on web usage

/mappings

This gives us details about all Spring MVC routes

/trace

This shows details about past requests

Pinging our app for general health

Each of these endpoints can be visited using our browser or using other tools such as curl. For example, let's assume we ran spring run ops.groovy and then opened up another shell. From the second shell, let's run the following curl command:

$ curl localhost:8080/health
{"status":"UP"}

This immediately solves our first need listed previously. We can inform the system administrator that he or she can write a management script to interrogate our app's health.

Gathering metrics

Be warned that each of these endpoints serves up a compact JSON document. Generally speaking, command-line curl probably isn't the best option. While it's convenient on *nix and Mac systems, the content is dense and hard to read. It's more practical to have:

Assuming we have JSONView installed, the following screenshot shows a listing of metrics:

It lists counters for each HTTP endpoint. According to this, /metrics has been visited four times with a successful 200 status code. Someone tried to access /foo, but it failed with a 404 error code. The report also lists gauges for each endpoint, reporting the last response time. In this case, /metrics took 2 milliseconds. Also included are some memory stats as well as the total CPUs available.

Tip

It's important to realize that the metrics start at 0. To generate some numbers, you might want to first click on some links before visiting /metrics.

The following screenshot shows a trace report:

It shows the entire web request and response for curl localhost:8080/health.

This provides a basic framework of metrics to satisfy our manager's needs. It's important to understand that metrics gathered by Spring Boot Actuator aren't persistent across application restarts. So to gather long-term data, we have to gather them and then write them elsewhere.

With these options, we can perform the following:

  • Write a script that gathers metrics every hour and appends them to a running spreadsheet somewhere else in the filesystem, such as a shared drive. This might be simple, but probably also crude.

  • To step it up, we can dump the data into a Hadoop filesystem for raw collection and configure Spring XD (http://projects.spring.io/spring-xd/) to consume it. Spring XD stands for Spring eXtreme Data. It is an open source product that makes it incredibly easy to chain together sources and sinks comprised of many components, such as HTTP endpoints, Hadoop filesystems, Redis metrics, and RabbitMQ messaging. Unfortunately, there is no space to dive into this subject.

Tip

With any monitoring, it's important to check that we aren't taxing the system too heavily. The same container responding to business-related web requests is also serving metrics data, so it will be wise to engage profilers periodically to ensure that the whole system is performing as expected.

Detailed management with CRaSH

So what can we do when we receive that 2:00 a.m. phone call from the Ops center? After either coming in or logging in remotely, we can access the convenient CRaSH shell we configured.

Every time the app launches, it generates a random password for SSH access and prints this to the local console:

2014-06-11 23:00:18.822 ... : Configuring property ssh.port=2000 from properties
2014-06-11 23:00:18.823 ... : Configuring property ssh.auth-timeout=600000 fro...
2014-06-11 23:00:18.824 ... : Configuring property ssh.idle-timeout=600000 fro...
2014-06-11 23:00:18.824 ... : Configuring property auth=simple from properties
2014-06-11 23:00:18.824 ... : Configuring property auth.simple.username=user f...
2014-06-11 23:00:18.824 ... : Configuring property auth.simple.password=bdbe4a...

We can easily see that there's SSH access on port 2000 via a user if we use this information to log in:

$ ssh -p 2000 [email protected]
Password authentication
Password:
  .   ____          _            __ _ _
/\\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _' | \ \ \ \
\\/  ___)| |_)| | | | | || (_| |  ) ) ) )
  '  |____| .__|_| |_|_| |_\__, | / / / /
=========|_|==============|___/=/_/_/_/
:: Spring Boot ::  (v1.1.6.RELEASE) on retina
>

There's a fistful of commands:

  • help: This gets a listing of available commands

  • dashboard: This gets a graphic, text-based display of all the threads, environment properties, memory, and other things

  • autoconfig: This prints out a report of which Spring Boot auto-configuration rules were applied and which were skipped (and why)

All of the previous commands have man pages:

> man autoconfig
NAME
      autoconfig - Display auto configuration report from ApplicationContext

SYNOPSIS
      autoconfig [-h | --help]

STREAM
      autoconfig <java.lang.Void, java.lang.Object>

PARAMETERS
      [-h | --help]
          Display this help message
...

There are many commands available to help manage our application. More details are available at http://www.crashub.org/1.3/reference.html.

This is just a taste of what's possible. Later on in Chapter 2, Quick Start with Java, and Chapter 3, Debugging and Managing Your App, we will dig in deeper to discover ways to write custom metrics, custom health checks, and custom CRaSH commands.

 

Summary


We rapidly crafted a Spring MVC application using the Spring stack on top of Apache Tomcat with little configuration from our end. We plugged in jQuery (and could have included CSS if we wanted). We also learned how to write both JUnit and Spock test cases. We plugged in Spring Boot's Actuator module as well as the CRaSH remote shell, configuring it with metrics, health, and management features so that we can monitor it in production by merely adding two lines of extra code.

In the next chapter, we'll do something quite similar, but with pure Java and a sample application that focuses on fetching GitHub information.

About the Author

  • Greg L. Turnquist

    Greg L. Turnquist has been a software professional since 1997. In 2002, he joined the senior software team that worked on Harris' $3.5 billion FAA telco program, architecting mission-critical enterprise apps while managing a software team. He provided after-hours support to a nation-wide system and is no stranger to midnight failures and software triages. In 2010, he joined the SpringSource division of VMware, which was spun off into Pivotal in 2013.

    As a test-bitten script junky, Java geek, and JavaScript Padawan, he is a member of the Spring Data team and the lead for Spring Session MongoDB. He has made key contributions to Spring Boot, Spring HATEOAS, and Spring Data REST while also serving as editor-at-large for Spring's Getting Started Guides.

    Greg wrote technical best sellers Python Testing Cookbook and Learning Spring Boot, First Edition, for Packt Publishing. When he isn't slinging code, Greg enters the world of magic and cross swords, having written the speculative fiction action and adventure novel, Darklight.

    He completed his Master's degree in computer engineering at Auburn University and lives in the United States with his family.

    Browse publications by this author

Latest Reviews

(2 reviews total)
Excellent
Good
Book Title
Unlock this full book FREE 10 day trial
Start Free Trial