Open Credo

February 24, 2014 | Cloud Native, Microservices

Experiences with Spring Boot

Last year some of us attended the London Spring eXchange where we encountered a new and interesting tool that Pivotal was working on: Spring Boot. Since then we had the opportunity to see what it’s capable of in a live project and we were deeply impressed.

WRITTEN BY

David Borsos

David Borsos

Experiences with Spring Boot

Only write code that you need to

Our project involved the creation of several independent microservices that provided functionality for consumers via REST/HTTP APIs. Most of them had to communicate with a data store, too. Each of these services had a single, well-defined function, for example handling common user data or dealing with webshop-baskets, etc…

Using Spring Boot, our average-sized service contained (excluding unit tests)

  • 11 Java classes
  • 400 lines of code
  • No Spring XMLs
  • Some essential configuration values (e.g. webserver ports) externalized in a property file
  • Maven pom files
  • Logback configuration XMLs (this is not necessary, but we opted to customize Logback)

In exchange for that we got

  • Production-ready services
  • Basic health-check and monitoring functions (see the section about Actuator below)
  • Pre-configured, embedded Tomcat server
  • Executable JAR packaging with all dependencies included
  • Very little overall configuration overhead (i.e. we just had to configure what we wanted to customize)

After we got acquainted with Boot, it took one of us a couple of hours to create a new, fully functional, decoupled service from scratch.

How to use it?

To leverage Spring Boot, you need to set the spring-boot-starter-parent project as your Maven parent (Gradle is supported as well, we used Maven) and put some dependencies in your pom.

One of the great ideas in Boot is that it will import default configurations based on the contents of your classpath. If you want to build a Spring MVC application, just pull spring-boot-starter-web. You need messaging with RabbitMQ? Add spring-boot-starter-amqp; it’s there and it’s working. It is really that simple.

In addition, using the Boot starter as your Maven parent gives you default library versions for many commonly used Java libraries like core Spring, JUnit, Logback, Guava, etc… so you don’t even have to worry about versions. The flip side is that when you actually need a specific version of a library, you have to override these defaults and may encounter incompatibilities.

Example: a minimalistic Spring MVC service

The example we are presenting is similar to the official Spring Boot quick start which it is a very good way to get started. We will add some comments on what is happening and start with a slightly different setup.

The pom file

The first step is to configure Maven for Spring Boot. This means that you need to

  • Set your project parent to spring-boot-starter-parent
  • Import spring-boot-starter-web, because this is a webservice
  • We also recommend setting property java.version to 1.7 (will default to 1.5 otherwise)

Be aware that because Spring Boot is not yet released to production, you’ll need to set a custom repository (http://repo.spring.io/milestone) to pull all the dependencies.

Java classes

In this example we are going to add two Java classes, one responsible for startup and basic configuration, the other is our MVC controller:

@EnableAutoConfiguration
@ComponentScan("com.opencredo.springboot")
public class HelloConfiguration {
    public static void main(String[] args) {
        SpringApplication.run(HelloConfiguration.class, args);
    }
}
@Controller
public class HelloController {
    @RequestMapping("/hello")
    @ResponseBody
    public String hello() {
        return "Hello World!";
    }
}

Please note the following:

  • We are relying on Spring’s annotation and package-scan based approach to configure our controller
  • @EnableAutoConfiguration is specific to Spring Boot and declaring it will result in a lot of pre-defined configuration pulled to our Spring Application Context (like the embedded Tomcat container)
  • SpringApplication is another Boot-specific component, it’s the default entry point for most of the Spring Boot applications and will take care of the Spring Application Context for us

And that is all you actually need. At this point you should be able to start this application from your favourite IDE, launching class HelloConfiguration. Then visit http://localhost:8080/hello which should result in “Hello World!” being displayed in your browser.

Packaging the application

As we previously mentioned, Spring Boot gives an easy way of packaging applications into a self-contained executable jar file. To do this, just add the spring-boot-maven-plugin build plugin to Maven (you may have to add http://repo.spring.io/milestone as a plugin repository).

Packaging the project should result in the creation of two files:

  • spring-boot-example-0.0.1-SNAPSHOT.jar.original
  • spring-boot-example-0.0.1-SNAPSHOT.jar

The .original file is the output of the default Maven compiler, while the other one is the jar file enhanced by Spring Boot’s plugin. If you check the sizes, you’ll notice that the latter one is significantly larger (ours is almost 10 megabytes). The reason for this is that Spring Boot packages all the dependencies necessary to run the application into this single jar executable jar.

If you now start this (simply java -jar), you should see the same output that was in your IDE’s log window, and when checking http://localhost:8080/hello, you should see the same behavior.

Overriding default configuration

The fact that Spring Boot pre-configures almost everything that you need for you is very useful when starting the development. However the time will soon come when you will want more control over what is happening. Fortunately it is quite easy to override these defaults.

Using property files

By default Spring Boot will look for a property file in the package root directory called application.properties, this is a good place to customize your application. By Maven conventions, place this file into the src/main/resources directory so your build artefacts will be generated correctly. For example let’s set the contents to:

server.port=11000

This will cause the embedded Tomcat to listen on port 11000 instead of 8080. If you now restart your service, you should use http://localhost:11000/hello to get access.

Finding out what is given by default and what you can override is probably probably the biggest problem with Spring Boot at the moment. There is no comprehensive documentation about all the options, but the code in org.springframework.boot.autoconfigure.* packages is a good starting point. (e.g. server.port is bound to a field in org.springframework.boot.autoconfigure.web.ServerProperties as of Boot 1.0.0.RC3).

Overriding with command line arguments

If you need more execution-specific parameter use, you can do it. The usual convention of the property overriding chain: defaults < property files < Java VM arguments is still valid, but Spring Boot will also give you Spring’s command-line argument property source: with double dashes (“–”) arguments when executing your application, you can specify property overrides:

$ java -jar spring-boot-example-0.0.1-SNAPSHOT.jar --server.port=12000

As you probably have already figured out, this will result in your webserver listening on port 12000 and your application available on http://localhost:12000/hello

Support for Spring profiles

Spring Boot actively supports the usage of Spring Profiles. First, to activate a profile, you can use the double-dash command line argument syntax: –spring.profiles.active and list those that you want activated. Additionally, you can name your property files in the following way:

application-{profile}.properties

And only those that match one of the active profiles will get loaded.

Regarding your Spring beans, you can rely on the @Profile annotation to work as expected.

Overriding default beans

When pulling a spring-boot-starter project as a dependency, Boot will declare the most commonly needed beans. For example, in case of a web project, you will get a DispatcherServlet without having to do anything (usually, you can configure these default beans with externalized properties).

In the majority of the cases this will be sufficient. However, if you want to have more control over these beans, just declare them as you normally would and your beans will override the ones given by Boot (in fact, Boot won’t even instantiate any of its default beans if you have an overriding bean).

The Spring Boot Actuator

Although meaning a slight detour from the general Spring Boot description, when talking about web applications built with it, we cannot leave the Actuator unmentioned. It’s a Spring Boot module that immediately gives your Spring-based web applications basic health check and monitoring interfaces. To use it just add Maven dependency spring-boot-starter-actuator.

If you now recompile and restart your service, you’ll notice that a lot more endpoints are being mapped (this is printed to the log during startup). Some of these are:

  • /health – returns “ok” as text/plain content which is useful for simple service monitoring
  • /env – check environment configuration, property file and command line argument overrides, active profiles
  • /metrics – basic statistics on your service endpoints (e.g. hit count, error count)
  • /dump – thread dump
  • /trace – the latest HTTP request/response pairs

You can access/modify (or change completely if you wish) the behavior for most of these. For example, if you want to add a custom metric, just inject a MetricRepository in your business beans, and start using it, it’ll get exposed via the Actuator /metrics interface.

More details on the Actuator.

Caveats

Although most features that Spring Boot gives you are extremely useful and work very well immediately, we encountered a few cases where a bit of caution is recommended:

  • Spring Boot will import and use Logback and SLF4J as default loggers. If you want to use something else (e.g. Log4J) or one of your dependencies transitively imports it, you need to be careful and use the appropriate logger bridges. Some combinations may result in your applications not starting at all. Maven exclusions for transitive dependencies will come handy.
  • The Spring Boot Maven Builder packages executable jar files in a specific way, effectively adding multiple levels of nested jar files. This is a problem if your libraries want to extract contents from the nested jar files as Java won’t be able to resolve that resource path. Consider using a different packaging mechanism like Shade or AppAssembler in such cases. Spring Boot Maven Parent comes with a basic configuration for Shade, but the preferred choice should be the Boot-builder.
  • We advise some level of caution if you want to use embedded application servers and JSPs with Spring Boot, there may be some limitations.

Conclusion

Despite the fact that Spring Boot has not even reached its first production release yet, it was surprisingly stable and very useful. Even though there are a few caveats to be aware of, we didn’t encounter any issues that we couldn’t solve in a reasonably easy way. Given that we needed the ability to quickly get new services and modules running and we wanted to build them on a Java/Spring stack, it was the perfect tool for us.

 

This blog is written exclusively by the OpenCredo team. We do not accept external contributions.

RETURN TO BLOG

SHARE

Twitter LinkedIn Facebook Email

SIMILAR POSTS

Blog