Search icon CANCEL
Subscription
0
Cart icon
Your Cart (0 item)
Close icon
You have no products in your basket yet
Arrow left icon
Explore Products
Best Sellers
New Releases
Books
Videos
Audiobooks
Learning Hub
Conferences
Free Learning
Arrow right icon

Getting Started with Spring Boot

Save for later
  • 17 min read
  • 03 Jan 2017

article-image

In this article by, Greg Turnquist, author of the book, Learning Spring Boot – Second Edition, we will cover the following topics:

  • Introduction
  • Creating a bare project using http://start.spring.io
  • Seeing how to run our app straight inside our IDE with no stand alone containers

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

Perhaps you've heard about Spring Boot? It's only cultivated the most popular explosion in software development in years. Clocking millions of downloads per month, the community has exploded since it's debut in 2013.

I hope you're ready for some fun, because we are going to take things to the next level as we use Spring Boot to build a social media platform. We'll explore its many valuable features all the way from tools designed to speed up development efforts to production-ready support as well as cloud native features.

Despite some rapid fire demos you might have caught on YouTube, Spring Boot isn't just for quick demos. Built atop the de facto standard toolkit for Java, the Spring Framework, Spring Boot will help us build this social media platform with lightning speed AND stability.

In this article, we'll get a quick kick off with Spring Boot using Java the programming language. Maybe that makes you chuckle? People have been dinging Java for years as being slow, bulky, and not the means for agile shops. Together, we'll see how that is not the case.

At any time, if you're interested in a more visual medium, feel free to checkout my Learning Spring Boot [Video] at https://www.packtpub.com/application-development/learning-spring-boot-video.

What is step #1 when we get underway with a project? We visit Stack Overflow and look for an example project to build a project!

Seriously, the amount of time spent adapting another project's build file, picking dependencies, and filling in other details about our project adds up.

At the Spring Initializr (http://start.spring.io), we can enter minimal details about our app, pick our favorite build system, the version of Spring Boot we wish to use, and then choose our dependencies off a menu. Click the Download button, and we have a free standing, ready-to-run application.

In this article, let's take a quick test drive and build small web app. We can start by picking Gradle from the dropdown. Then, select 1.4.1.BUILD-SNAPSHOT as the version of Spring Boot we wish to use.

Next, we need to pick our application's coordinates:

  • Group - com.greglturnquist.learningspringboot
  • Artifact - learning-spring-boot

Now comes the fun part. We get to pick the ingredients for our application like picking off a delicious menu. If we start typing, for example, "Web", into the Dependencies box, we'll see several options appear. To see all the available options, click on the Switch to the full version link toward the bottom.

There are lots of overrides, such as switching from JAR to WAR, or using an older version of Java. You can also pick Kotlin or Groovy as the primary language for your application. For starters, in this day and age, there is no reason to use anything older than Java 8. And JAR files are the way to go. WAR files are only needed when applying Spring Boot to an old container.

To build our social media platform, we need a few ingredients as shown:

  • Web (embedded Tomcat + Spring MVC)
  • WebSocket
  • JPA (Spring Data JPA)
  • H2 (embedded SQL data store)
  • Thymeleaf template engine
  • Lombok (to simplify writing POJOs)

The following diagram shows an overview of these ingredients:

getting-started-spring-boot-img-0

With these items selected, click on Generate Project.

There are LOTS of other tools that leverage this site. For example, IntelliJ IDEA lets you create a new project inside the IDE, giving you the same options shown here. It invokes the web site's REST API, and imports your new project. You can also interact with the site via cURL or any other REST-based tool.

Now let's unpack that ZIP file and see what we've got:

  • a build.gradle build file
  • a Gradle wrapper, so there's no need to install Gradle
  • a LearningSpringBootApplication.java application class
  • an application.properties file
  • a LearningSpringBootApplicationTests.java test class

We built an empty Spring Boot project. Now what? Before we sink our teeth into writing code, let's take a peek at the build file. It's quite terse, but carries some key bits.

Starting from the top:

buildscript {
  ext {
    springBootVersion = '1.4.1.BUILD-SNAPSHOT'
  }
  repositories {
    mavenCentral()
    maven { url "https://repo.spring.io/snapshot" }
    maven { url "https://repo.spring.io/milestone" }
  }
  dependencies {
    classpath("org.springframework.boot:spring-boot-gradle-
      plugin:${springBootVersion}")
  }
}

This contains the basis for our project:

  • springBootVersion shows us we are using Spring Boot 1.4.1.BUILD-SNAPSHOT
  • The Maven repositories it will pull from are listed next
  • Finally, we see the spring-boot-gradle-plugin, a critical tool for any Spring Boot project

The first piece, the version of Spring Boot, is important. That's because Spring Boot comes with a curated list of 140 third party library versions extending well beyond the Spring portfolio and into some of the most commonly used libraries in the Java ecosystem. By simply changing the version of Spring Boot, we can upgrade all these libraries to newer versions known to work together.

There is an extra project, the Spring IO Platform (https://spring.io/platform), which includes an additional 134 curated versions, bringing the total to 274.

The repositories aren't as critical, but it's important to add milestones and snapshots if fetching a library not released to Maven central or hosted on some vendor's local repository. Thankfully, the Spring Initializr does this for us based on the version of Spring Boot selected on the site.

Finally, we have the spring-boot-gradle-plugin (and there is a corresponding spring-boot-maven-plugin for Maven users). This plugin is responsible for linking Spring Boot's curated list of versions with the libraries we select in the build file. That way, we don't have to specify the version number.

Additionally, this plugin hooks into the build phase and bundle our application into a runnable über JAR, also known as a shaded or fat JAR.

Java doesn't provide a standardized way to load nested JAR files into the classpath. Spring Boot 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.4.1.BUILD-SNAPSHOT/reference/htmlsingle/#executable-jar.

With an über JAR in hand, we only need put it on a thumb drive, and carry it to another machine, to a hundred virtual machines in the cloud or your data center, or anywhere else, and it simply runs where we can find a JVM.

Peeking a little further down in build.gradle, we can see the plugins that are enabled by default:

apply plugin: 'java'
apply plugin: 'eclipse'
apply plugin: 'spring-boot'
  • The java plugin indicates the various tasks expected for a Java project
  • The eclipse plugin helps generate project metadata for Eclipse users
  • The spring-boot plugin is where the actual spring-boot-gradle-plugin is activated

An up-to-date copy of IntelliJ IDEA can ready a plain old Gradle build file fine without extra plugins.

Which brings us to the final ingredient used to build our application: dependencies.

Spring Boot starters

No application is complete without specifying dependencies. A valuable facet of Spring Boot are its virtual packages. These are published packages that don't contain any code, but instead simply list other dependencies.

The following list shows all the dependencies we selected on the Spring Initializr site:

dependencies {
  compile('org.springframework.boot:spring-boot-starter-data-jpa')
  compile('org.springframework.boot:spring-boot-starter-
    thymeleaf')
  compile('org.springframework.boot:spring-boot-starter-web')
  compile('org.springframework.boot:spring-boot-starter-
    websocket')

  compile('org.projectlombok:lombok')
  runtime('com.h2database:h2')
  testCompile('org.springframework.boot:spring-boot-starter-test')
}

If you'll notice, most of these packages are Spring Boot starters:

  • spring-boot-starter-data-jpa pulls in Spring Data JPA, Spring JDBC, Spring ORM, and Hibernate
  • spring-boot-starter-thymeleaf pulls in Thymeleaf template engine along with Spring Web and the Spring dialect of Thymeleaf
  • spring-boot-starter-web pulls in Spring MVC, Jackson JSON support, embedded Tomcat, and Hibernate's JSR-303 validators
  • spring-boot-starter-websocket pulls in Spring WebSocket and Spring Messaging

These starter packages allow us to quickly grab the bits we need to get up and running. Spring Boot starters have gotten so popular that lots of other third party library developers are crafting their own.

In addition to starters, we have three extra libraries:

Unlock access to the largest independent learning library in Tech for FREE!
Get unlimited access to 7500+ expert-authored eBooks and video courses covering every tech area you can think of.
Renews at £16.99/month. Cancel anytime
  • Project Lombok makes it dead simple to define POJOs without getting bogged down in getters, setters, and others details.
  • H2 is an embedded database allowing us to write tests, noodle out solutions, and get things moving before getting involved with an external database.
  • spring-boot-starter-test pulls in Spring Boot Test, JSON Path, JUnit, AssertJ, Mockito, Hamcrest, JSON Assert, and Spring Test, all within test scope.

The value of this last starter, spring-boot-starter-test, cannot be overstated. With a single line, the most powerful test utilities are at our fingertips, allowing us to write unit tests, slice tests, and full blown our-app-inside-embedded-Tomcat tests. It's why this starter is included in all projects without checking a box on the Spring Initializr site.

Now to get things off the ground, we need to shift focus to the tiny bit of code written for us by the Spring Initializr.

Running a Spring Boot application

The fabulous http://start.spring.io website created a tiny class, LearningSpringBootApplication as shown in the following code:

package com.greglturnquist.learningspringboot;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class LearningSpringBootApplication {

  public static void main(String[] args) {
    SpringApplication.run(
      LearningSpringBootApplication.class, args);
  }
}

This tiny class is actually a fully operational web application!

  • The @SpringBootApplication annotation tells Spring Boot, when launched, to scan recursively for Spring components inside this package and register them. It also tells Spring Boot to enable autoconfiguration, a process where beans are automatically created based on classpath settings, property settings, and other factors. Finally, it indicates that this class itself can be a source for Spring bean definitions.
  • It holds a public static void main(), a simple method to run the application. There is no need to drop this code into an application server or servlet container. We can just run it straight up, inside our IDE. The amount of time saved by this feature, over the long haul, adds up fast.
  • SpringApplication.run() points Spring Boot at the leap off point. In this case, this very class. But it's possible to run other classes.

This little class is runnable. Right now! In fact, let's give it a shot.

.   ____          _            __ _ _
/\ / ___'_ __ _ _(_)_ __  __ _    
( ( )___ | '_ | '_| | '_ / _` |    
\/  ___)| |_)| | | | | || (_| |  ) ) ) )
  '  |____| .__|_| |_|_| |___, | / / / /
=========|_|==============|___/=/_/_/_/
:: Spring Boot ::  (v1.4.1.BUILD-SNAPSHOT)

2016-09-18 19:52:44.214: Starting 
LearningSpringBootApplication on ret...
2016-09-18 19:52:44.217: No active profile set, falling 
back to defaul...
2016-09-18 19:52:44.513: Refreshing 
org.springframework.boot.context.e...
2016-09-18 19:52:45.785: Bean 
'org.springframework.transaction.annotat...
2016-09-18 19:52:46.188: Tomcat initialized with port(s): 
8080 (http)
2016-09-18 19:52:46.201: Starting service Tomcat
2016-09-18 19:52:46.202: Starting Servlet Engine: Apache 
Tomcat/8.5.5
2016-09-18 19:52:46.323: Initializing Spring embedded 
WebApplicationCo...
2016-09-18 19:52:46.324: Root WebApplicationContext: 
initialization co...
2016-09-18 19:52:46.466: Mapping servlet: 
'dispatcherServlet' to [/]
2016-09-18 19:52:46.469: Mapping filter: 
'characterEncodingFilter' to:...
2016-09-18 19:52:46.470: Mapping filter: 
'hiddenHttpMethodFilter' to: ...
2016-09-18 19:52:46.470: Mapping filter: 
'httpPutFormContentFilter' to...
2016-09-18 19:52:46.470: Mapping filter: 
'requestContextFilter' to: [/*]
2016-09-18 19:52:46.794: Building JPA container 
EntityManagerFactory f...
2016-09-18 19:52:46.809: HHH000204: Processing 
PersistenceUnitInfo [
    name: default
    ...]
2016-09-18 19:52:46.882: HHH000412: Hibernate Core 
{5.0.9.Final}
2016-09-18 19:52:46.883: HHH000206: hibernate.properties 
not found
2016-09-18 19:52:46.884: javassist
2016-09-18 19:52:46.976: HCANN000001: Hibernate Commons 
Annotations {5...
2016-09-18 19:52:47.169: Using dialect: 
org.hibernate.dialect.H2Dialect
2016-09-18 19:52:47.358: HHH000227: Running hbm2ddl schema 
export
2016-09-18 19:52:47.359: HHH000230: Schema export complete
2016-09-18 19:52:47.390: Initialized JPA 
EntityManagerFactory for pers...
2016-09-18 19:52:47.628: Looking for @ControllerAdvice: 
org.springfram...
2016-09-18 19:52:47.702: Mapped "{[/error]}" onto public 
org.springfra...
2016-09-18 19:52:47.703: Mapped 
"{[/error],produces=[text/html]}" onto...
2016-09-18 19:52:47.724: Mapped URL path [/webjars/**] onto 
handler of...
2016-09-18 19:52:47.724: Mapped URL path [/**] onto handler 
of type [c...
2016-09-18 19:52:47.752: Mapped URL path [/**/favicon.ico] 
onto handle...
2016-09-18 19:52:47.778: Cannot find template location: 
classpath:/tem...
2016-09-18 19:52:48.229: Registering beans for JMX exposure 
on startup
2016-09-18 19:52:48.278: Tomcat started on port(s): 8080 
(http)
2016-09-18 19:52:48.282: Started 
LearningSpringBootApplication in 4.57...

Scrolling through the output, we can see several things:

  • The banner at the top gives us a readout of the version of Spring Boot. (BTW, you can create your own ASCII art banner by creating either banner.txt or banner.png into src/main/resources/)
  • Embedded Tomcat is initialized on port 8080, indicating it's ready for web requests
  • Hibernate is online with the H2 dialect enabled
  • A few Spring MVC routes are registered, such as /error, /webjars, a favicon.ico, and a static resource handler
  • And the wonderful Started LearningSpringBootApplication in 4.571 seconds message

Spring Boot uses embedded Tomcat, so there's no need to install a container on our target machine. Non-web apps don't even require Apache Tomcat. The JAR 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.

How does Spring Boot use embedded Tomcat among other things? As mentioned earlier, it has autoconfiguration meaning it has Spring beans that are created based on different conditions. When Spring Boot sees Apache Tomcat on the classpath, it creates an embedded Tomcat instance along with several beans to support that.

When it spots Spring MVC on the classpath, it creates view resolution engines, handler mappers, and a whole host of other beans needed to support that, letting us focus on coding custom routes.

With H2 on the classpath, it spins up an in-memory, embedded SQL data store.

Spring Data JPA will cause Spring Boot to craft an EntityManager along with everything else needed to start speaking JPA, letting us focus on defining repositories.

At this stage, we have a running web application, albeit an empty one. There are no custom routes and no means to handle data. But we can add some real fast.

Let's draft a simple REST controller:

package com.greglturnquist.learningspringboot;

import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class HomeController {

  @GetMapping
  public String greeting(@RequestParam(required = false,
    defaultValue = "") String name) {
    return name.equals("")
    ? "Hey!"
    : "Hey, " + name + "!";
  }

}

Let's examine this tiny REST controller in detail:

  • The @RestController annotation indicates that we don't want to render views, but instead write the results straight into the response body.
  • @GetMapping is Spring's shorthand annotation for @RequestMapping(method = RequestMethod.GET, …[]). In this case, it defaults the route to "/".
  • Our greeting() method has one argument: @RequestParam(required = false, defaultValue = "") String name. It indicates that this value can be requested via an HTTP query (?name=Greg), the query isn't required, and in case it's missing, supply an empty string.
  • Finally, we are returning one of two messages depending on whether or not name is empty using Java's classic ternary operator.

If we re-launch the LearningSpringBootApplication in our IDE, we'll see a new entry in the console.

2016-09-18 20:13:08.149: Mapped "{[],methods=[GET]}" onto public
java....

We can then ping our new route in the browser at http://localhost:8080 and http://localhost:8080?name=Greg. Try it out!

That's nice, but since we picked Spring Data JPA, how hard would it be to load some sample data and retrieve it from another route? (Spoiler alert: not hard at all.)

We can start out by defining a simple Chapter entity to capture book details as shown in the following code:

package com.greglturnquist.learningspringboot;

import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;

import lombok.Data;

@Data
@Entity
public class Chapter {

  @Id @GeneratedValue
  private Long id;

  private String name;
  private Chapter() {
    // No one but JPA uses this.
  }

  public Chapter(String name) {
    this.name = name;
  }

}

This little POJO let's us the details about the chapter of a book as follows:

  • The @Data annotation from Lombok will generate getters, setters, a toString() method, a constructor for all required fields (those marked final), an equals() method, and a hashCode() method.
  • The @Entity annotation flags this class as suitable for storing in a JPA data store.
  • The id field is marked with JPA's @Id and @GeneratedValue annotations, indicating this is the primary key, and that writing new rows into the corresponding table will create a PK automatically.
  • Spring Data JPA will by default create a table named CHAPTER with two columns, ID, and NAME.
  • The key field is name, which is populated by the publicly visible constructor. JPA requires a no-arg constructor, so we have included one, but marked it private so no one but JPA may access it.

To interact with this entity and it's corresponding table in H2, we could dig in and start using the autoconfigured EntityManager supplied by Spring Boot. By why do that, when we can declare a repository-based solution?

To do so, we'll create an interface defining the operations we need.

Check out this simple interface:

package com.greglturnquist.learningspringboot;

import org.springframework.data.repository.CrudRepository;

public interface ChapterRepository
  extends CrudRepository<Chapter, Long> {

}

This declarative interface creates a Spring Data repository as follows:

  • CrudRepository extends Repository, a Spring Data Commons marker interface that signals Spring Data to create a concrete implementation while also capturing domain information.
  • CrudRepository, also from Spring Data Commons, has some pre-defined CRUD operations (save, delete, deleteAll, findOne, findAll).
  • It specifies the entity type (Chapter) and the type of the primary key (Long).

Spring Data JPA will automatically wire up a concrete implementation of our interface.

Spring Data doesn't engage in code generation. Code generation has a sordid history of being out of date at some of the worst times. Instead, Spring Data uses proxies and other mechanisms to support all these operations. Never forget - the code you don't write has no bugs.

With Chapter and ChapterRepository defined, we can now pre-load the database, as shown in the following code:

package com.greglturnquist.learningspringboot;

import org.springframework.boot.CommandLineRunner;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class LoadDatabase {

  @Bean
  CommandLineRunner init(ChapterRepository repository) {
    return args -> {
      repository.save(
        new Chapter("Quick start with Java"));
      repository.save(
        new Chapter("Reactive Web with Spring Boot"));
      repository.save(
        new Chapter("...and more!"));
    };
  }

}

This class will be automatically scanned in by Spring Boot and run in the following way:

  • @Configuration marks this class as a source of beans.
  • @Bean indicates that the return value of init() is a Spring Bean. In this case, a CommandLineRunner.
  • Spring Boot runs all CommandLineRunner beans after the entire application is up and running. This bean definition is requesting a copy of the ChapterRepository.
  • Using Java 8's ability to coerce the args → {} lambda function into a CommandLineRunner, we are able to write several save() operations, pre-loading our data.

With this in place, all that's left is write a REST controller to serve up the data!

package com.greglturnquist.learningspringboot;

import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class ChapterController {

  private final ChapterRepository repository;

  public ChapterController(ChapterRepository repository) {
    this.repository = repository;
  }

  @GetMapping("/chapters")
  public Iterable<Chapter> listing() {
    return repository.findAll();
  }
}

This controller is able to serve up our data as follows:

  • @RestController indicates this is another REST controller.
  • Constructor injection is used to automatically load it with a copy of the ChapterRepository. With Spring, if there is a only one constructor call, there is no need to include an @Autowired annotation.
  • @GetMapping tells Spring that this is the place to route /chapters calls. In this case, it returns the results of the findAll() call found in CrudRepository.

If we re-launch our application and visit http://localhost:8080/chapters, we can see our pre-loaded data served up as a nicely formatted JSON document:

getting-started-spring-boot-img-1

It's not very elaborate, but this small collection of classes has helped us quickly define a slice of functionality. And if you'll notice, we spent zero effort configuring JSON converters, route handlers, embedded settings, or any other infrastructure.

Spring Boot is designed to let us focus on functional needs, not low level plumbing.

Summary

So in this article we introduced the Spring Boot concept in brief and we rapidly crafted a Spring MVC application using the Spring stack on top of Apache Tomcat with little configuration from our end.

Resources for Article:


Further resources on this subject: