Search icon CANCEL
Subscription
0
Cart icon
Your Cart (0 item)
Close icon
You have no products in your basket yet
Save more on your purchases now! discount-offer-chevron-icon
Savings automatically calculated. No voucher code required.
Arrow left icon
Explore Products
Best Sellers
New Releases
Books
Videos
Audiobooks
Learning Hub
Conferences
Free Learning
Arrow right icon
Microservices with Spring Boot 3 and Spring Cloud, Third Edition
Microservices with Spring Boot 3 and Spring Cloud, Third Edition

Microservices with Spring Boot 3 and Spring Cloud, Third Edition: Build resilient and scalable microservices using Spring Cloud, Istio, and Kubernetes , Third Edition

Arrow left icon
Profile Icon Magnus Larsson AB Profile Icon Magnus Larsson
Arrow right icon
€33.99
Full star icon Full star icon Full star icon Full star icon Empty star icon 4 (23 Ratings)
Paperback Aug 2023 706 pages 3rd Edition
eBook
€17.99 €26.99
Paperback
€33.99
Subscription
Free Trial
Renews at €18.99p/m
Arrow left icon
Profile Icon Magnus Larsson AB Profile Icon Magnus Larsson
Arrow right icon
€33.99
Full star icon Full star icon Full star icon Full star icon Empty star icon 4 (23 Ratings)
Paperback Aug 2023 706 pages 3rd Edition
eBook
€17.99 €26.99
Paperback
€33.99
Subscription
Free Trial
Renews at €18.99p/m
eBook
€17.99 €26.99
Paperback
€33.99
Subscription
Free Trial
Renews at €18.99p/m

What do you get with Print?

Product feature icon Instant access to your digital eBook copy whilst your Print order is Shipped
Product feature icon Paperback book shipped to your preferred address
Product feature icon Download this book in EPUB and PDF formats
Product feature icon Access this title in our online reader with advanced features
Product feature icon DRM FREE - Read whenever, wherever and however you want
Product feature icon AI Assistant (beta) to help accelerate your learning
Table of content icon View table of contents Preview book icon Preview Book

Microservices with Spring Boot 3 and Spring Cloud, Third Edition

Introduction to Spring Boot

In this chapter, we will be introduced to how to build a set of cooperating microservices using Spring Boot, focusing on how to develop functionality that delivers business value. The challenges with microservices that we pointed out in the previous chapter will be considered only to some degree, but they will be addressed to their full extent in later chapters.

We will develop microservices that contain business logic based on plain Spring Beans and expose REST APIs using Spring WebFlux. The APIs will be documented based on the OpenAPI Specification using springdoc-openapi. To make the data processed by the microservices persistent, we will use Spring Data to store data in both SQL and NoSQL databases.

Since Spring Boot v2.0 was released in March 2018, it has become much easier to develop reactive microservices, including non-blocking synchronous REST APIs. To develop message-based asynchronous services, we will use Spring Cloud Stream. Refer to Chapter 1, Introduction to Microservices, the Reactive microservices section, for more information.

In November 2022, Spring Boot 3.0 was released. It is based on Spring Framework 6.0 and Jakarta EE 9, also being compatible with Jakarta EE 10. Java 17, the current long-term support (LTS) release, is required as the minimum Java version.

Finally, we will use Docker to run our microservices as containers. This will allow us to start and stop our microservice landscape, including database servers and a message broker, with a single command.

That’s a lot of technologies and frameworks, so let’s go through each of them briefly to see what they are about!

In this chapter, we will introduce the following open source projects:

  • Spring Boot

(This section also includes an overview of what’s new in v3.0 and on how to migrate v2 applications.)

  • Spring WebFlux
  • springdoc-openapi
  • Spring Data
  • Spring Cloud Stream
  • Docker

More details about each product will be provided in upcoming chapters.

Technical requirements

This chapter does not contain any source code that can be downloaded, nor does it require any tools to be installed.

Spring Boot

Spring Boot, and the Spring Framework that Spring Boot is based on, is a great framework for developing microservices in Java.

When the Spring Framework v1.0 was released back in 2004, one of its main goals was to address the overly complex J2EE standard (short for Java 2 Platform, Enterprise Edition) with its infamous and heavyweight deployment descriptors. The Spring Framework provided a much more lightweight development model based on the concept of dependency injection. The Spring Framework also used far more lightweight XML configuration files compared to the deployment descriptors in J2EE.

To make things even worse with the J2EE standard, the heavyweight deployment descriptors actually came in two types:

  • Standard deployment descriptors, describing the configuration in a standardized way
  • Vendor-specific deployment descriptors, mapping the configuration to vendor-specific features in the vendor’s application server

In 2006, J2EE was renamed Java EE, short for Java Platform, Enterprise Edition. In 2017, Oracle submitted Java EE to the Eclipse Foundation. In February 2018, Java EE was renamed Jakarta EE. The new name, Jakarta EE, also affects the names of the Java packages defined by the standard, requiring developers to perform package renaming when upgrading to Jakarta EE, as described in the Migrating a Spring Boot 2 application section. Over the years, while the Spring Framework gained increasing popularity, the functionality in the Spring Framework grew significantly. Slowly, the burden of setting up a Spring application using the no-longer-so-lightweight XML configuration file became a problem.

In 2014, Spring Boot v1.0 was released, addressing these problems!

Convention over configuration and fat JAR files

Spring Boot targets the fast development of production-ready Spring applications by being strongly opinionated about how to set up both core modules from the Spring Framework and third-party products, such as libraries that are used for logging or connecting to a database. Spring Boot does that by applying a number of conventions by default, minimizing the need for configuration. Whenever required, each convention can be overridden by writing some configuration, case by case. This design pattern is known as convention over configuration and minimizes the need for initial configuration.

Configuration, when required, is, in my opinion, written best using Java and annotations. The good old XML-based configuration files can still be used, although they are significantly smaller than before Spring Boot was introduced.

Added to the usage of convention over configuration, Spring Boot also favors a runtime model based on a standalone JAR file, also known as a fat JAR file. Before Spring Boot, the most common way to run a Spring application was to deploy it as a WAR file on a Java EE web server, such as Apache Tomcat. WAR file deployment is still supported by Spring Boot.

A fat JAR file contains not only the classes and resource files of the application itself but also all the JAR files the application depends on. This means that the fat JAR file is the only JAR file required to run the application; that is, we only need to transfer one JAR file to an environment where we want to run the application instead of transferring the application’s JAR file along with all the JAR files the application depends on.

Starting a fat JAR requires no separately installed Java EE web server, such as Apache Tomcat. Instead, it can be started with a simple command such as java -jar app.jar, making it a perfect choice for running in a Docker container! If the Spring Boot application, for example, uses HTTP to expose a REST API, it will also contain an embedded web server.

Code examples for setting up a Spring Boot application

To better understand what this means, let’s look at some source code examples.

We will only look at some small fragments of code here to point out the main features. For a fully working example, you’ll have to wait until the next chapter!

The magic @SpringBootApplication annotation

The convention-based autoconfiguration mechanism can be initiated by annotating the application class (that is, the class that contains the static main method) with the @SpringBootApplication annotation. The following code shows this:

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

The following functionality will be provided by this annotation:

  • It enables component scanning, that is, looking for Spring components and configuration classes in the package of the application class and all its sub-packages.
  • The application class itself becomes a configuration class.
  • It enables autoconfiguration, where Spring Boot looks for JAR files in the classpath that it can configure automatically. For example, if you have Tomcat in the classpath, Spring Boot will automatically configure Tomcat as an embedded web server.

Component scanning

Let’s assume we have the following Spring component in the package of the application class (or in one of its sub-packages):

@Component
public class MyComponentImpl implements MyComponent { ...

Another component in the application can get this component automatically injected, also known as auto-wired, using the @Autowired annotation:

public class AnotherComponent {
  private final MyComponent myComponent;
  @Autowired
  public AnotherComponent(MyComponent myComponent) {
    this.myComponent = myComponent;
  }

I prefer using constructor injection (over field and setter injection) to keep the state in my components immutable. An immutable state is important if you want to be able to run the component in a multithreaded runtime environment.

If we want to use components that are declared in a package outside the application’s package, for example, a utility component shared by multiple Spring Boot applications, we can complement the @SpringBootApplication annotation in the application class with a @ComponentScan annotation:

package se.magnus.myapp;
@SpringBootApplication
@ComponentScan({"se.magnus.myapp","se.magnus.util" })
public class MyApplication {

We can now auto-wire components from the se.magnus.util package in the application code, for example, a utility component named MyUtility, as follows:

package se.magnus.util;
@Component
public class MyUtility { ...

This utility component can be auto-wired in an application component like so:

package se.magnus.myapp.services;
public class AnotherComponent {
 private final MyUtility myUtility;
 @Autowired
 public AnotherComponent(MyUtility myUtility) {
   this.myUtility = myUtility;
 }

Java-based configuration

If we want to override Spring Boot’s default configuration or we want to add our own configuration, we can simply annotate a class with @Configuration and it will be picked up by the component scanning mechanism we described previously.

For example, if we want to set up a filter in the processing of HTTP requests (handled by Spring WebFlux, which is described in the following section) that writes a log message at the beginning and the end of the processing, we can configure a log filter, as follows:

@Configuration
public class SubscriberApplication {
  @Bean
  public Filter logFilter() {
    CommonsRequestLoggingFilter filter = new 
        CommonsRequestLoggingFilter();
    filter.setIncludeQueryString(true);
    filter.setIncludePayload(true);
    filter.setMaxPayloadLength(5120);
    return filter;
  }

We can also place the configuration directly in the application class since the @SpringBootApplication annotation implies the @Configuration annotation.

That’s all for now about Spring Boot, but before moving to the next component, let’s see what is new in Spring Boot 3.0 and how to migrate a Spring Boot 2 application.

What’s new in Spring Boot 3.0

For the scope of this book, the most important new items in Spring Boot 3.0 are the following:

  • Observability

    Spring Boot 3.0 comes with improved support for observability, adding built-in support for distributed tracing to the already existing support for metrics and logging in previous Spring Boot releases. The new distributed tracing support is based on a new Observability API in Spring Framework v6.0 and a new module named Micrometer Tracing. Micrometer Tracing is based on Spring Cloud Sleuth, which is now deprecated. Chapter 14, Understand Distributed Tracing, covers how to use the new support for observability and distributed tracing.

  • Native compilation

    Spring Boot 3.0 also comes with support for compiling Spring Boot applications to native images, which are standalone executable files. A native-compiled Spring Boot application starts significantly faster and consumes less memory. Chapter 23, Native-Compiled Java Microservices, describes how to native compile microservices based on Spring Boot.

  • Virtual threads

    Finally, Spring Boot 3.0 comes with support for lightweight threads called virtual threads from the OpenJDK Project Loom. Virtual threads are expected to simplify the programming model for developing reactive non-blocking microservices, for example, compared to the programming model used in Project Reactor and various Spring components. Virtual threads are currently only available as a preview in Java 19. They also currently lack support for composability features, for example, required to build microservices that concurrently aggregate information from other microservices. Therefore, virtual threads will not be covered in this book. Chapter 7, Developing Reactive Microservices, covers how virtual threads can be implemented using Project Reactor and Spring WebFlux.

Migrating a Spring Boot 2 application

If you already have applications based on Spring Boot 2, you might be interested in understanding what it takes to migrate to Spring Boot 3.0. Here is a list of actions you need to take:

  1. Pivotal recommends first upgrading Spring Boot 2 applications to the latest v2.7.x release since their migration guide assumes you are on v2.7.
  2. Ensure you have Java 17 or later installed, both in your development and runtime environments. If your Spring Boot applications are deployed as Docker containers, you need to ensure that your company approves the usage of Docker images based on Java 17 or newer releases.
  3. Remove calls to deprecated methods in Spring Boot 2.x. All deprecated methods are removed in Spring Boot 3.0, so you must ensure that your application does not call any of these methods. To see exactly where calls are being made in your application, you can enable the lint:deprecation flag in the Java compiler using (assuming the use of Gradle):
    tasks.withType(JavaCompile) {
        options.compilerArgs += ['-Xlint:deprecation']
    }
    
  4. Rename all imports of javax packages that are now part of Jakarta EE to jakarta.
  5. For libraries that are not managed by Spring, you need to ensure that you are using versions that are Jakarta compliant, that is, using jakarta packages.
  6. For breaking changes and other important migration information, read through:

    https://github.com/spring-projects/spring-boot/wiki/Spring-Boot-3.0-Migration-Guide

    https://docs.spring.io/spring-security/reference/migration/index.html

  1. Ensure that you have end-to-end black-box tests that verify the functionality of your application. Run these tests before and after the migration to ensure that the application’s functionality has not been affected by the migration.

When migrating the source code of the previous edition of this book to Spring Boot 3.0, the most time-consuming part was figuring out how to handle breaking changes in the Spring Security configuration; see Chapter 11, Securing Access to APIs, for details. As an example, the following configuration of the authorization server in the previous edition needed to be updated:

@Bean
SecurityFilterChain defaultSecurityFilterChain(HttpSecurity http) throws Exception {
  http
    .authorizeRequests(authorizeRequests -> authorizeRequests
      .antMatchers("/actuator/**").permitAll()

This configuration looks like the following with Spring Boot 3.0:

@Bean
SecurityFilterChain defaultSecurityFilterChain(HttpSecurity http) throws Exception {
  http
    .authorizeHttpRequests(authorizeRequests -> authorizeRequests
      .requestMatchers("/actuator/**").permitAll()

The end-to-end test script, test-em-all.bash, that comes with each chapter turned out to be indispensable in verifying that the functionality was unaffected after the migration of each chapter.

Now that we have learned about Spring Boot, let’s talk about Spring WebFlux.

Spring WebFlux

Spring Boot 3.0 is based on the Spring Framework 6.0, which has built-in support for developing reactive applications. The Spring Framework uses Project Reactor as the base implementation of its reactive support and also comes with a new web framework, Spring WebFlux, which supports the development of reactive, that is, non-blocking, HTTP clients and services.

Spring WebFlux supports two different programming models:

  • An annotation-based imperative style, similar to the already existing web framework, Spring Web MVC, but with support for reactive services
  • A new function-oriented model based on routers and handlers

In this book, we will use the annotation-based imperative style to demonstrate how easy it is to move REST services from Spring Web MVC to Spring WebFlux and then start to refactor the services so that they become fully reactive.

Spring WebFlux also provides a fully reactive HTTP client, WebClient, as a complement to the existing RestTemplate client.

Spring WebFlux supports running on a servlet container based on the Jakarta Servlet specification v5.0 or higher, such as Apache Tomcat, but also supports reactive non-servlet-based embedded web servers such as Netty (https://netty.io/).

The Servlet specification is a specification in the Java EE platform that standardizes how to develop Java applications that communicate using web protocols such as HTTP.

Code examples of setting up a REST service

Before we can create a REST service based on Spring WebFlux, we need to add Spring WebFlux (and the dependencies that Spring WebFlux requires) to the classpath for Spring Boot to be detected and configured during startup. Spring Boot provides a large number of convenient starter dependencies that bring in a specific feature, together with the dependencies each feature normally requires. So, let’s use the starter dependency for Spring WebFlux and then see what a simple REST service looks like!

Starter dependencies

In this book, we will use Gradle as our build tool, so the Spring WebFlux starter dependency will be added to the build.gradle file. It looks like this:

implementation('org.springframework.boot:spring-boot-starter-webflux')

You might be wondering why we don’t specify a version number. We will talk about that when we look at a complete example in Chapter 3, Creating a Set of Cooperating Microservices!

When the microservice is started up, Spring Boot will detect Spring WebFlux on the classpath and configure it, as well as other things such as starting up an embedded web server. Spring WebFlux uses Netty by default, which we can see from the log output:

2023-03-09 15:23:43.592 INFO 17429 --- [ main] o.s.b.web.embedded.netty.NettyWebServer : Netty started on port(s): 8080

If we want to switch from Netty to Tomcat as our embedded web server, we can override the default configuration by excluding Netty from the starter dependency and adding the starter dependency for Tomcat:

implementation('org.springframework.boot:spring-boot-starter-webflux') 
{
 exclude group: 'org.springframework.boot', module: 'spring-boot-
 starter-reactor-netty'
}
implementation('org.springframework.boot:spring-boot-starter-tomcat')

After restarting the microservice, we can see that Spring Boot picked Tomcat instead:

2023-03-09 18:23:44.182 INFO 17648 --- [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat initialized with port(s): 8080 (http)

Property files

As you can see from the preceding examples, the web server is started up using port 8080. If you want to change the port, you can override the default value using a property file. Spring Boot application property files can either be a .properties file or a YAML file. By default, they are named application.properties and application.yml, respectively.

In this book, we will use YAML files so that the HTTP port used by the embedded web server can be changed to, for example, 7001. By doing this, we can avoid port collisions with other microservices running on the same server. To do this, we can add the following line to the application.yml file:

server.port: 7001

When we begin to develop our microservices as containers in Chapter 4, Deploying Our Microservices Using Docker, port collisions will no longer be a problem. Each container has its own hostname and port range, so all microservices can use, for example, port 8080 without colliding with each other.

Sample RestController

Now, with Spring WebFlux and an embedded web server of our choice in place, we can write a REST service in the same way as when using Spring MVC, that is, as a RestController:

@RestController
public class MyRestService {
  @GetMapping(value = "/my-resource", produces = "application/json")
  List<Resource> listResources() {
    …
  }

The @GetMapping annotation on the listResources() method will map the Java method to an HTTP GET API on the host:8080/myResource URL. The return value of the List<Resource> type will be converted into JSON.

Now that we’ve talked about Spring WebFlux, let’s see how we can document the APIs we develop using Spring WebFlux.

springdoc-openapi

One very important aspect of developing APIs, for example, RESTful services, is how to document them so that they are easy to use. The Swagger specification from SmartBear Software is one of the most widely used ways of documenting RESTful services. Many leading API gateways have native support for exposing the documentation of RESTful services using the Swagger specification.

In 2015, SmartBear Software donated the Swagger specification to the Linux Foundation under the OpenAPI Initiative and created the OpenAPI Specification. The name Swagger is still used for the tooling provided by SmartBear Software.

springdoc-openapi is an open source project, separate from the Spring Framework, that can create OpenAPI-based API documentation at runtime. It does so by examining the application, for example, inspecting WebFlux and Swagger-based annotations.

We will look at full source code examples in upcoming chapters, but for now, the following condensed screenshot (removed parts are marked with “”) of a sample API documentation will do:

Graphical user interface, application, Teams  Description automatically generated

Figure 2.1: Sample API documentation visualized using Swagger UI

Note the big Execute button, which can be used to actually try out the API, not just read its documentation!

springdoc-openapi helps us to document the APIs exposed by our microservices. Now, let’s move on to Spring Data.

Spring Data

Spring Data comes with a common programming model for persisting data in various types of database engines, ranging from traditional relational databases (SQL databases) to various types of NoSQL database engines, such as document databases (for example, MongoDB), key-value databases (for example, Redis), and graph databases (for example, Neo4j).

The Spring Data project is divided into several subprojects, and in this book, we will use Spring Data subprojects for MongoDB and JPA that have been mapped to a MySQL database.

JPA stands for Jakarta Persistence API and is a Java specification about how to handle relational data. Please go to https://jakarta.ee/specifications/persistence/ for the latest specifications. Jakarta EE 9 is based on Jakarta Persistence 3.0.

The two core concepts of the programming model in Spring Data are entities and repositories. Entities and repositories generalize how data is stored and accessed from the various types of databases. They provide a common abstraction but still support adding database-specific behavior to the entities and repositories. These two core concepts are briefly explained together with some illustrative code examples as we proceed through this chapter. Remember that more details will be provided in the upcoming chapters!

Even though Spring Data provides a common programming model for different types of databases, this doesn’t mean that you will be able to write portable source code. For example, switching the database technology from a SQL database to a NoSQL database will, in general, not be possible without some changes in the source code!

Entity

An entity describes the data that will be stored by Spring Data. Entity classes are, in general, annotated with a mix of generic Spring Data annotations and annotations that are specific to each database technology.

For example, an entity that will be stored in a relational database can be annotated with JPA annotations such as the following:

import jakarta.persistence.Entity;
import jakarta.persistence.Id;
import jakarta.persistence.IdClass;
import jakarta.persistence.Table;
@Entity
@IdClass(ReviewEntityPK.class)
@Table(name = "review")
public class ReviewEntity {
 @Id private int productId;
 @Id private int reviewId;
 private String author;
 private String subject;
 private String content;

If an entity is to be stored in a MongoDB database, annotations from the Spring Data MongoDB subproject can be used together with generic Spring Data annotations. For example, consider the following code:

import org.springframework.data.annotation.Id;
import org.springframework.data.annotation.Version;
import org.springframework.data.mongodb.core.mapping.Document;
@Document
public class RecommendationEntity {
    @Id
    private String id;
    @Version
    private int version;
    private int productId;
    private int recommendationId;
    private String author;
    private int rate;
    private String content;

The @Id and @Version annotations are generic annotations, while the @Document annotation is specific to the Spring Data MongoDB subproject.

This can be revealed by studying the import statements; the import statements that contain mongodb come from the Spring Data MongoDB subproject.

Repositories

Repositories are used to store and access data from different types of databases. In its most basic form, a repository can be declared as a Java interface, and Spring Data will generate its implementation on the fly using opinionated conventions. These conventions can be overridden and/or complemented by additional configuration and, if required, some Java code.

Spring Data also comes with some base Java interfaces, for example, CrudRepository, to make the definition of a repository even simpler. The base interface, CrudRepository, provides us with standard methods for create, read, update, and delete operations.

To specify a repository for handling the JPA entity ReviewEntity, we only need to declare the following:

import org.springframework.data.repository.CrudRepository;
public interface ReviewRepository extends 
  CrudRepository<ReviewEntity, ReviewEntityPK> {
  
  Collection<ReviewEntity> findByProductId(int productId);
}

In this example we use a class, ReviewEntityPK, to describe a composite primary key. It looks as follows:

public class ReviewEntityPK implements Serializable {
    public int productId;
    public int reviewId;
}

We have also added an extra method, findByProductId, which allows us to look up Review entities based on productid – a field that is part of the primary key. The naming of the method follows a naming convention defined by Spring Data that allows Spring Data to generate the implementation of this method on the fly as well.

If we want to use the repository, we can simply inject it and then start to use it, for example:

private final ReviewRepository repository;
@Autowired
public ReviewService(ReviewRepository repository) {
 this.repository = repository;
}
public void someMethod() {
  repository.save(entity);
  repository.delete(entity);
  repository.findByProductId(productId);

Added to the CrudRepository interface, Spring Data also provides a reactive base interface, ReactiveCrudRepository, which enables reactive repositories. The methods in this interface do not return objects or collections of objects; instead, they return Mono and Flux objects. Mono and Flux objects are, as we will see in Chapter 7, Developing Reactive Microservices, reactive streams that are capable of returning either 0...1 or 0...m entities as they become available on the stream.

The reactive-based interface can only be used by Spring Data subprojects that support reactive database drivers; that is, they are based on non-blocking I/O. The Spring Data MongoDB subproject supports reactive repositories, while Spring Data JPA does not.

Specifying a reactive repository for handling the MongoDB entity, RecommendationEntity, as described previously, might look something like the following:

import org.springframework.data.repository.reactive.ReactiveCrudRepository;
import reactor.core.publisher.Flux;
public interface RecommendationRepository extends ReactiveCrudRepository<RecommendationEntity, String> {
    Flux<RecommendationEntity> findByProductId(int productId);
}

This concludes the section on Spring Data. Now let’s see how we can use Spring Cloud Stream to develop message-based asynchronous services.

Spring Cloud Stream

We will not focus on Spring Cloud in this part; we will do that in Part 2 of the book, from Chapter 8, Introduction to Spring Cloud, to Chapter 14, Understanding Distributed Tracing. However, we will bring in one of the modules that’s part of Spring Cloud: Spring Cloud Stream. Spring Cloud Stream provides a streaming abstraction over messaging, based on the publish and subscribe integration pattern. Spring Cloud Stream currently comes with built-in support for Apache Kafka and RabbitMQ. A number of separate projects exist that provide integration with other popular messaging systems. See https://github.com/spring-cloud?q=binder for more details.

The core concepts in Spring Cloud Stream are as follows:

  • Message: A data structure that’s used to describe data sent to and received from a messaging system.
  • Publisher: Sends messages to the messaging system, also known as a Supplier.
  • Subscriber: Receives messages from the messaging system, also known as a Consumer.
  • Destination: Used to communicate with the messaging system. Publishers use output destinations and subscribers use input destinations. Destinations are mapped by the specific binders to queues and topics in the underlying messaging system.
  • Binder: A binder provides the actual integration with a specific messaging system, similar to what a JDBC driver does for a specific type of database.

The actual messaging system to be used is determined at runtime, depending on what is found on the classpath. Spring Cloud Stream comes with opinionated conventions on how to handle messaging. These conventions can be overridden by specifying a configuration for messaging features such as consumer groups, partitioning, persistence, durability, and error handling; for example, retries and dead letter queue handling.

Code examples for sending and receiving messages

To better understand how all this fits together, let’s look at some source code examples.

Spring Cloud Stream comes with two programming models: one older and nowadays deprecated model based on the use of annotations (for example, @EnableBinding, @Output, and @StreamListener) and one newer model based on writing functions. In this book, we will use functional implementations.

To implement a publisher, we only need to implement the java.util.function.Supplier functional interface as a Spring Bean. For example, the following is a publisher that publishes messages as a String:

@Bean
public Supplier<String> myPublisher() {
   return () -> new Date().toString();
}

A subscriber is implemented as a Spring Bean implementing the java.util.function.Consumer functional interface. For example, the following is a subscriber that consumes messages as Strings:

@Bean
public Consumer<String> mySubscriber() {
   return s -> System.out.println("ML RECEIVED: " + s);
}

It is also possible to define a Spring Bean that processes messages, meaning that it both consumes and publishes messages. This can be done by implementing the java.util.function.Function functional interface. For example, a Spring Bean that consumes incoming messages and publishes a new message after some processing (both messages are Strings in this example):

@Bean
public Function<String, String> myProcessor() {
   return s -> "ML PROCESSED: " + s;
}

To make Spring Cloud Stream aware of these functions, we need to declare them using the spring.cloud.function.definition configuration property. For example, for the three functions defined previously, this would look as follows:

spring.cloud.function:
  definition: myPublisher;myProcessor;mySubscriber

Finally, we need to tell Spring Cloud Stream what destination to use for each function. To connect our three functions so that our processor consumes messages from our publisher and our subscriber consumes messages from the processor, we can supply the following configuration:

spring.cloud.stream.bindings:
  myPublisher-out-0:
    destination: myProcessor-in
  myProcessor-in-0:
    destination: myProcessor-in
  myProcessor-out-0:
    destination: myProcessor-out
  mySubscriber-in-0:
    destination: myProcessor-out

This will result in the following message flow:

myPublisher → myProcessor → mySubscriber

A supplier is triggered by Spring Cloud Stream by default every second, so we could expect output like the following if we start a Spring Boot application including the functions and configuration described previously:

ML RECEIVED: ML PROCESSED: Wed Mar 09 16:28:30 CET 2021
ML RECEIVED: ML PROCESSED: Wed Mar 09 16:28:31 CET 2021
ML RECEIVED: ML PROCESSED: Wed Mar 09 16:28:32 CET 2021
ML RECEIVED: ML PROCESSED: Wed Mar 09 16:28:33 CET 2021

In cases where the supplier should be triggered by an external event instead of using a timer, the StreamBridge helper class can be used. For example, if a message should be published to the processor when a REST API, sampleCreateAPI, is called, the code could look like the following:

@Autowired
private StreamBridge streamBridge;
@PostMapping
void sampleCreateAPI(@RequestBody String body) {
  streamBridge.send("myProcessor-in-0", body);
}

Now that we understand the various Spring APIs, let’s learn a bit about Docker and containers in the next section.

Docker

I assume that Docker and the concept of containers need no in-depth introduction. Docker made the concept of containers as a lightweight alternative to virtual machines very popular in 2013. A container is actually a process in a Linux host that uses Linux namespaces to provide isolation between different containers, in terms of their use of global system resources such as users, processes, filesystems, and networking. Linux control groups (also known as cgroups) are used to limit the amount of CPU and memory that a container is allowed to consume.

Compared to a virtual machine that uses a hypervisor to run a complete copy of an operating system in each virtual machine, the overhead in a container is a fraction of the overhead in a traditional virtual machine.

This leads to much faster startup times and significantly lower overhead in terms of CPU and memory usage.

The isolation that’s provided for a container is, however, not considered to be as secure as the isolation that’s provided for a virtual machine. With the release of Windows Server 2016, Microsoft supports the use of Docker in Windows servers.

During the last few years, a lightweight form of virtual machines has evolved. It mixes the best of traditional virtual machines and containers, providing virtual machines with a footprint and startup time similar to containers and with the same level of secure isolation provided by traditional virtual machines. Some examples are Amazon Firecracker and Microsoft Windows Subsystem for Linux v2 (WSL2). For more information, see https://firecracker-microvm.github.io and https://docs.microsoft.com/en-us/windows/wsl/.

Containers are very useful during both development and testing. Being able to start up a complete system landscape of cooperating microservices and resource managers (for example, database servers, messaging brokers, and so on) with a single command for testing is simply amazing.

For example, we can write scripts in order to automate end-to-end tests of our microservice landscape. A test script can start up the microservice landscape, run tests using the exposed APIs, and tear down the landscape. This type of automated test script is very useful, both for running locally on a developer PC before pushing code to a source code repository, and to be executed as a step in a delivery pipeline. A build server can run these types of tests in its continuous integration and deployment process whenever a developer pushes code to the source repository.

For production usage, we need a container orchestrator such as Kubernetes. We will come back to container orchestrators and Kubernetes later in this book.

For most of the microservices we will look at in this book, a Dockerfile such as the following is all that is required to run the microservice as a Docker container:

FROM openjdk:17
MAINTAINER Magnus Larsson <magnus.larsson.ml@gmail.com>
EXPOSE 8080
ADD ./build/libs/*.jar app.jar
ENTRYPOINT ["java","-jar","/app.jar"]

If we want to start and stop many containers with one command, Docker Compose is the perfect tool. Docker Compose uses a YAML file to describe the containers to be managed.

For our microservices, it might look something like the following:

product:
 build: microservices/product-service
recommendation:
 build: microservices/recommendation-service
review:
  build: microservices/review-service
composite:
  build: microservices/product-composite-service
  ports:
    - "8080:8080"

Let me explain the preceding source code a little:

  • The build directive is used to specify which Dockerfile to use for each microservice. Docker Compose will use it to build a Docker image and then launch a Docker container based on that Docker image.
  • The ports directive for the composite service is used to expose port 8080 on the server where Docker runs. On a developer’s machine, this means that the port of the composite service can be reached simply by using localhost:8080!

All the containers in the YAML files can be managed with simple commands such as the following:

  • docker-compose up -d: Starts all containers. -d means that the containers run in the background, not locking the terminal from where the command was executed.
  • docker-compose down: Stops and removes all containers.
  • docker-compose logs -f --tail=0: Prints out log messages from all containers. -f means that the command will not complete, and instead waits for new log messages. --tail=0 means that we don’t want to see any previous log messages, only new ones.

For a full list of Docker Compose commands, see https://docs.docker.com/compose/reference/.

This was a brief introduction to Docker. We will go into more detail about Docker starting with Chapter 4, Deploying Our Microservices Using Docker.

Summary

In this chapter, we have been introduced to Spring Boot and complementary open source tools that can be used to build cooperating microservices.

Spring Boot is used to simplify the development of Spring-based, production-ready applications, such as microservices. It is strongly opinionated in terms of how to set up both core modules from the Spring Framework and third-party tools. Using Spring WebFlux, we can develop microservices that expose reactive, that is, non-blocking, REST services. To document these REST services, we can use springdoc-openapi to create OpenAPI-based documentation for the APIs. If we need to persist data used by the microservices, we can use Spring Data, which provides an elegant abstraction for accessing and manipulating persistent data using entities and repositories. Spring Data’s programming model is similar, but not fully portable between different types of databases, for example, relational, document, key-value, and graph databases.

If we prefer sending messages asynchronously between our microservices, we can use Spring Cloud Stream, which provides a streaming abstraction over messaging. Spring Cloud Stream comes with out-of-the-box support for Apache Kafka and RabbitMQ but can be extended to support other messaging brokers using custom binders. Finally, Docker makes the concept of containers as a lightweight alternative to virtual machines easy to use. Based on Linux namespaces and control groups, containers provide isolation similar to what traditional virtual machines provide, but with a significantly lower overhead in terms of CPU and memory usage.

In the next chapter, we will take our first small steps, creating microservices with minimalistic functionality using Spring Boot and Spring WebFlux.

Questions

  1. What is the purpose of the @SpringBootApplication annotation?
  2. What are the main differences between the older Spring component for developing REST services, Spring Web MVC, and the new Spring WebFlux?
  3. How does springdoc-openapi help a developer document REST APIs?
  4. What is the function of a repository in Spring Data and what is the simplest possible implementation of a repository?
  5. What is the purpose of a binder in Spring Cloud Stream?
  6. What is the purpose of Docker Compose?
Left arrow icon Right arrow icon
Download code icon Download Code

Key benefits

  • Build cloud-native production-ready microservices and stay ahead of the curve
  • Understand the challenges of building large-scale microservice architectures
  • Learn how to get the best out of the latest updates, including Spring Boot 3, Spring Cloud, Kubernetes, and Istio

Description

Looking to build and deploy microservices but not sure where to start? Check out Microservices with Spring Boot 3 and Spring Cloud, Third Edition. With a practical approach, you'll begin with simple microservices and progress to complex distributed applications. Learn essential functionality and deploy microservices using Kubernetes and Istio. This book covers Java 17, Spring Boot 3, and Spring Cloud 2022. Java EE packages are replaced with the latest Jakarta EE packages. Code examples are updated and deprecated APIs have been replaced, providing the most up to date information. Gain knowledge of Spring's AOT module, observability, distributed tracing, and Helm 3 for Kubernetes packaging. Start with Docker Compose to run microservices with databases and messaging services. Progress to deploying microservices on Kubernetes with Istio. Explore persistence, resilience, reactive microservices, and API documentation with OpenAPI. Learn service discovery with Netflix Eureka, edge servers with Spring Cloud Gateway, and monitoring with Prometheus, Grafana, and the EFK stack. By the end, you'll build scalable microservices using Spring Boot and Spring Cloud.

Who is this book for?

If you're a Java or Spring Boot developer learning how to build microservice landscapes from scratch, then this book is for you. To get started, you need some prior experience in building apps with Java or Spring Boot.

What you will learn

  • Build reactive microservices using Spring Boot
  • Develop resilient and scalable microservices using Spring Cloud
  • Use OAuth 2.1/OIDC and Spring Security to protect public APIs
  • Implement Docker to bridge the gap between development, testing, and production
  • Deploy and manage microservices with Kubernetes
  • Apply Istio for improved security, observability, and traffic management
  • Write and run automated microservice tests with JUnit, test containers, Gradle, and bash
  • Use Spring AOT and GraalVM to native compile the microservices
  • Use Micrometer Tracing for distributed tracing
Estimated delivery fee Deliver to Denmark

Premium delivery 7 - 10 business days

€17.95
(Includes tracking information)

Product Details

Country selected
Publication date, Length, Edition, Language, ISBN-13
Publication date : Aug 31, 2023
Length: 706 pages
Edition : 3rd
Language : English
ISBN-13 : 9781805128694
Languages :
Concepts :
Tools :

What do you get with Print?

Product feature icon Instant access to your digital eBook copy whilst your Print order is Shipped
Product feature icon Paperback book shipped to your preferred address
Product feature icon Download this book in EPUB and PDF formats
Product feature icon Access this title in our online reader with advanced features
Product feature icon DRM FREE - Read whenever, wherever and however you want
Product feature icon AI Assistant (beta) to help accelerate your learning
Estimated delivery fee Deliver to Denmark

Premium delivery 7 - 10 business days

€17.95
(Includes tracking information)

Product Details

Publication date : Aug 31, 2023
Length: 706 pages
Edition : 3rd
Language : English
ISBN-13 : 9781805128694
Languages :
Concepts :
Tools :

Packt Subscriptions

See our plans and pricing
Modal Close icon
€18.99 billed monthly
Feature tick icon Unlimited access to Packt's library of 7,000+ practical books and videos
Feature tick icon Constantly refreshed with 50+ new titles a month
Feature tick icon Exclusive Early access to books as they're written
Feature tick icon Solve problems while you work with advanced search and reference features
Feature tick icon Offline reading on the mobile app
Feature tick icon Simple pricing, no contract
€189.99 billed annually
Feature tick icon Unlimited access to Packt's library of 7,000+ practical books and videos
Feature tick icon Constantly refreshed with 50+ new titles a month
Feature tick icon Exclusive Early access to books as they're written
Feature tick icon Solve problems while you work with advanced search and reference features
Feature tick icon Offline reading on the mobile app
Feature tick icon Choose a DRM-free eBook or Video every month to keep
Feature tick icon PLUS own as many other DRM-free eBooks or Videos as you like for just €5 each
Feature tick icon Exclusive print discounts
€264.99 billed in 18 months
Feature tick icon Unlimited access to Packt's library of 7,000+ practical books and videos
Feature tick icon Constantly refreshed with 50+ new titles a month
Feature tick icon Exclusive Early access to books as they're written
Feature tick icon Solve problems while you work with advanced search and reference features
Feature tick icon Offline reading on the mobile app
Feature tick icon Choose a DRM-free eBook or Video every month to keep
Feature tick icon PLUS own as many other DRM-free eBooks or Videos as you like for just €5 each
Feature tick icon Exclusive print discounts

Frequently bought together


Stars icon
Total 103.97
Modern API Development with Spring 6 and Spring Boot 3
€33.99
Microservices with Spring Boot 3 and Spring Cloud, Third Edition
€33.99
Full Stack Development with Spring Boot 3 and React
€35.99
Total 103.97 Stars icon

Table of Contents

25 Chapters
Introduction to Microservices Chevron down icon Chevron up icon
Introduction to Spring Boot Chevron down icon Chevron up icon
Creating a Set of Cooperating Microservices Chevron down icon Chevron up icon
Deploying Our Microservices Using Docker Chevron down icon Chevron up icon
Adding an API Description Using OpenAPI Chevron down icon Chevron up icon
Adding Persistence Chevron down icon Chevron up icon
Developing Reactive Microservices Chevron down icon Chevron up icon
Introduction to Spring Cloud Chevron down icon Chevron up icon
Adding Service Discovery Using Netflix Eureka Chevron down icon Chevron up icon
Using Spring Cloud Gateway to Hide Microservices behind an Edge Server Chevron down icon Chevron up icon
Securing Access to APIs Chevron down icon Chevron up icon
Centralized Configuration Chevron down icon Chevron up icon
Improving Resilience Using Resilience4j Chevron down icon Chevron up icon
Understanding Distributed Tracing Chevron down icon Chevron up icon
Introduction to Kubernetes Chevron down icon Chevron up icon
Deploying Our Microservices to Kubernetes Chevron down icon Chevron up icon
Implementing Kubernetes Features to Simplify the System Landscape Chevron down icon Chevron up icon
Using a Service Mesh to Improve Observability and Management Chevron down icon Chevron up icon
Centralized Logging with the EFK Stack Chevron down icon Chevron up icon
Monitoring Microservices Chevron down icon Chevron up icon
Installation Instructions for macOS Chevron down icon Chevron up icon
Installation Instructions for Microsoft Windows with WSL 2 and Ubuntu Chevron down icon Chevron up icon
Native-Complied Java Microservices Chevron down icon Chevron up icon
Other Books You May Enjoy Chevron down icon Chevron up icon
Index Chevron down icon Chevron up icon

Customer reviews

Most Recent
Rating distribution
Full star icon Full star icon Full star icon Full star icon Empty star icon 4
(23 Ratings)
5 star 65.2%
4 star 13%
3 star 0%
2 star 4.3%
1 star 17.4%
Filter icon Filter
Most Recent

Filter reviews by




Placeholder Oct 22, 2024
Full star icon Empty star icon Empty star icon Empty star icon Empty star icon 1
The pages are getting out of the book
Amazon Verified review Amazon
Amazon Customer Aug 18, 2024
Full star icon Empty star icon Empty star icon Empty star icon Empty star icon 1
Have received it today and started reading , Book pages are coming out one by one while reading , extremely poor quality binding.
Amazon Verified review Amazon
N/A Jul 19, 2024
Full star icon Full star icon Full star icon Full star icon Full star icon 5
These books Vedio part should also be available for mobile devices
Feefo Verified review Feefo
misbah rahman May 15, 2024
Full star icon Empty star icon Empty star icon Empty star icon Empty star icon 1
The Binding of book is really poor. The moment i took book in my hand, a page came out like a silk. Not recommended to get this book from the this seller until they sell a good binding book. You pay what they ask, so expecting a quality is not much espectation.
Amazon Verified review Amazon
Kumar Kartikeya May 07, 2024
Full star icon Empty star icon Empty star icon Empty star icon Empty star icon 1
The binding for this book is not good ... everytime im opening a page, page was coming out
Amazon Verified review Amazon
Get free access to Packt library with over 7500+ books and video courses for 7 days!
Start Free Trial

FAQs

What is the delivery time and cost of print book? Chevron down icon Chevron up icon

Shipping Details

USA:

'

Economy: Delivery to most addresses in the US within 10-15 business days

Premium: Trackable Delivery to most addresses in the US within 3-8 business days

UK:

Economy: Delivery to most addresses in the U.K. within 7-9 business days.
Shipments are not trackable

Premium: Trackable delivery to most addresses in the U.K. within 3-4 business days!
Add one extra business day for deliveries to Northern Ireland and Scottish Highlands and islands

EU:

Premium: Trackable delivery to most EU destinations within 4-9 business days.

Australia:

Economy: Can deliver to P. O. Boxes and private residences.
Trackable service with delivery to addresses in Australia only.
Delivery time ranges from 7-9 business days for VIC and 8-10 business days for Interstate metro
Delivery time is up to 15 business days for remote areas of WA, NT & QLD.

Premium: Delivery to addresses in Australia only
Trackable delivery to most P. O. Boxes and private residences in Australia within 4-5 days based on the distance to a destination following dispatch.

India:

Premium: Delivery to most Indian addresses within 5-6 business days

Rest of the World:

Premium: Countries in the American continent: Trackable delivery to most countries within 4-7 business days

Asia:

Premium: Delivery to most Asian addresses within 5-9 business days

Disclaimer:
All orders received before 5 PM U.K time would start printing from the next business day. So the estimated delivery times start from the next day as well. Orders received after 5 PM U.K time (in our internal systems) on a business day or anytime on the weekend will begin printing the second to next business day. For example, an order placed at 11 AM today will begin printing tomorrow, whereas an order placed at 9 PM tonight will begin printing the day after tomorrow.


Unfortunately, due to several restrictions, we are unable to ship to the following countries:

  1. Afghanistan
  2. American Samoa
  3. Belarus
  4. Brunei Darussalam
  5. Central African Republic
  6. The Democratic Republic of Congo
  7. Eritrea
  8. Guinea-bissau
  9. Iran
  10. Lebanon
  11. Libiya Arab Jamahriya
  12. Somalia
  13. Sudan
  14. Russian Federation
  15. Syrian Arab Republic
  16. Ukraine
  17. Venezuela
What is custom duty/charge? Chevron down icon Chevron up icon

Customs duty are charges levied on goods when they cross international borders. It is a tax that is imposed on imported goods. These duties are charged by special authorities and bodies created by local governments and are meant to protect local industries, economies, and businesses.

Do I have to pay customs charges for the print book order? Chevron down icon Chevron up icon

The orders shipped to the countries that are listed under EU27 will not bear custom charges. They are paid by Packt as part of the order.

List of EU27 countries: www.gov.uk/eu-eea:

A custom duty or localized taxes may be applicable on the shipment and would be charged by the recipient country outside of the EU27 which should be paid by the customer and these duties are not included in the shipping charges been charged on the order.

How do I know my custom duty charges? Chevron down icon Chevron up icon

The amount of duty payable varies greatly depending on the imported goods, the country of origin and several other factors like the total invoice amount or dimensions like weight, and other such criteria applicable in your country.

For example:

  • If you live in Mexico, and the declared value of your ordered items is over $ 50, for you to receive a package, you will have to pay additional import tax of 19% which will be $ 9.50 to the courier service.
  • Whereas if you live in Turkey, and the declared value of your ordered items is over € 22, for you to receive a package, you will have to pay additional import tax of 18% which will be € 3.96 to the courier service.
How can I cancel my order? Chevron down icon Chevron up icon

Cancellation Policy for Published Printed Books:

You can cancel any order within 1 hour of placing the order. Simply contact customercare@packt.com with your order details or payment transaction id. If your order has already started the shipment process, we will do our best to stop it. However, if it is already on the way to you then when you receive it, you can contact us at customercare@packt.com using the returns and refund process.

Please understand that Packt Publishing cannot provide refunds or cancel any order except for the cases described in our Return Policy (i.e. Packt Publishing agrees to replace your printed book because it arrives damaged or material defect in book), Packt Publishing will not accept returns.

What is your returns and refunds policy? Chevron down icon Chevron up icon

Return Policy:

We want you to be happy with your purchase from Packtpub.com. We will not hassle you with returning print books to us. If the print book you receive from us is incorrect, damaged, doesn't work or is unacceptably late, please contact Customer Relations Team on customercare@packt.com with the order number and issue details as explained below:

  1. If you ordered (eBook, Video or Print Book) incorrectly or accidentally, please contact Customer Relations Team on customercare@packt.com within one hour of placing the order and we will replace/refund you the item cost.
  2. Sadly, if your eBook or Video file is faulty or a fault occurs during the eBook or Video being made available to you, i.e. during download then you should contact Customer Relations Team within 14 days of purchase on customercare@packt.com who will be able to resolve this issue for you.
  3. You will have a choice of replacement or refund of the problem items.(damaged, defective or incorrect)
  4. Once Customer Care Team confirms that you will be refunded, you should receive the refund within 10 to 12 working days.
  5. If you are only requesting a refund of one book from a multiple order, then we will refund you the appropriate single item.
  6. Where the items were shipped under a free shipping offer, there will be no shipping costs to refund.

On the off chance your printed book arrives damaged, with book material defect, contact our Customer Relation Team on customercare@packt.com within 14 days of receipt of the book with appropriate evidence of damage and we will work with you to secure a replacement copy, if necessary. Please note that each printed book you order from us is individually made by Packt's professional book-printing partner which is on a print-on-demand basis.

What tax is charged? Chevron down icon Chevron up icon

Currently, no tax is charged on the purchase of any print book (subject to change based on the laws and regulations). A localized VAT fee is charged only to our European and UK customers on eBooks, Video and subscriptions that they buy. GST is charged to Indian customers for eBooks and video purchases.

What payment methods can I use? Chevron down icon Chevron up icon

You can pay with the following card types:

  1. Visa Debit
  2. Visa Credit
  3. MasterCard
  4. PayPal
What is the delivery time and cost of print books? Chevron down icon Chevron up icon

Shipping Details

USA:

'

Economy: Delivery to most addresses in the US within 10-15 business days

Premium: Trackable Delivery to most addresses in the US within 3-8 business days

UK:

Economy: Delivery to most addresses in the U.K. within 7-9 business days.
Shipments are not trackable

Premium: Trackable delivery to most addresses in the U.K. within 3-4 business days!
Add one extra business day for deliveries to Northern Ireland and Scottish Highlands and islands

EU:

Premium: Trackable delivery to most EU destinations within 4-9 business days.

Australia:

Economy: Can deliver to P. O. Boxes and private residences.
Trackable service with delivery to addresses in Australia only.
Delivery time ranges from 7-9 business days for VIC and 8-10 business days for Interstate metro
Delivery time is up to 15 business days for remote areas of WA, NT & QLD.

Premium: Delivery to addresses in Australia only
Trackable delivery to most P. O. Boxes and private residences in Australia within 4-5 days based on the distance to a destination following dispatch.

India:

Premium: Delivery to most Indian addresses within 5-6 business days

Rest of the World:

Premium: Countries in the American continent: Trackable delivery to most countries within 4-7 business days

Asia:

Premium: Delivery to most Asian addresses within 5-9 business days

Disclaimer:
All orders received before 5 PM U.K time would start printing from the next business day. So the estimated delivery times start from the next day as well. Orders received after 5 PM U.K time (in our internal systems) on a business day or anytime on the weekend will begin printing the second to next business day. For example, an order placed at 11 AM today will begin printing tomorrow, whereas an order placed at 9 PM tonight will begin printing the day after tomorrow.


Unfortunately, due to several restrictions, we are unable to ship to the following countries:

  1. Afghanistan
  2. American Samoa
  3. Belarus
  4. Brunei Darussalam
  5. Central African Republic
  6. The Democratic Republic of Congo
  7. Eritrea
  8. Guinea-bissau
  9. Iran
  10. Lebanon
  11. Libiya Arab Jamahriya
  12. Somalia
  13. Sudan
  14. Russian Federation
  15. Syrian Arab Republic
  16. Ukraine
  17. Venezuela