| "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
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 thehome()
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...
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 centralThe
spring-boot-starter-web
package is a Spring Boot package that pulls in all the dependencies needed for a Spring MVC appThe
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 instatic 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.
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:
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.
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 } }
Tip
This code sample is also part of Boot's set of tests at https://github.com/spring-projects/spring-boot/blob/master/spring-boot-cli/test-samples/spock.groovy.
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.
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 onapp.groovy
is includedAll required libraries are found in the
lib/
folderSpring 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.
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 incomingname
parameter and put it in the view'sModelAndView
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 thetext
value of this element. In this case, it concatenatesHello
with thename
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 inModelAndView
and proceeds to set thetext
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.
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 grabjquery.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.
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.
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
, andpublic
. 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.
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:
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.
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:
A JSON plugin installed in our browser (such as JSONView at http://jsonview.com)
A script that uses a JSON parsing library if we're writing a management script (such as Groovy's JsonSlurper at http://groovy.codehaus.org/gapi/groovy/json/JsonSlurper.html or JSONPath at https://code.google.com/p/json-path)
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.
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:
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.
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.