Modernizing our Spring Boot app

In this article by Greg L. Turnquist, the author of the book, Learning Spring Boot, we will discuss modernizing our Spring Boot app with JavaScript and adding production-ready support features.

(For more resources related to this topic, see here.)

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. 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/"
}

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 <gturnquist@pivotal.io>
[?] license: ASL
[?] homepage: http://blog.greglturnquist.com/category/learning-springboot
[?] 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 <gturnquist@pivotal.io>"
],
"description": "Learning Spring Boot - bower sample",
"license": "ASL",
"homepage": "http://blog.greglturnquist.com/category/learningspring-
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

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 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 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.

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 article 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:

Learning Spring Boot

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.

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:

Learning Spring Boot

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.

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.authtimeout=
600000 fro...
2014-06-11 23:00:18.824 ... : Configuring property ssh.idletimeout=
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 user@localhost
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.

Summary

In this article, we learned about modernizing our Spring Boot app with JavaScript and adding production-ready support features. 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.

Resources for Article:


Further resources on this subject:


You've been reading an excerpt of:

Learning Spring Boot

Explore Title