39,59 €
Developing, deploying, and operating cloud applications should be as easy as local applications. This should be the governing principle behind any cloud platform, library, or tool. Spring Cloud–an open-source library–makes it easy to develop JVM applications for the cloud. In this book, you will be introduced to Spring Cloud and will master its features from the application developer's point of view.
This book begins by introducing you to microservices for Spring and the available feature set in Spring Cloud. You will learn to configure the Spring Cloud server and run the Eureka server to enable service registration and discovery. Then you will learn about techniques related to load balancing and circuit breaking and utilize all features of the Feign client. The book now delves into advanced topics where you will learn to implement distributed tracing solutions for Spring Cloud and build message-driven microservice architectures. Before running an application on Docker container s, you will master testing and securing techniques with Spring Cloud.
Das E-Book können Sie in Legimi-Apps oder einer beliebigen App lesen, die das folgende Format unterstützen:
Seitenzahl: 464
Veröffentlichungsjahr: 2018
Copyright © 2018 Packt Publishing
All rights reserved. No part of this book may be reproduced, stored in a retrieval system, or transmitted in any form or by any means, without the prior written permission of the publisher, except in the case of brief quotations embedded in critical articles or reviews.
Every effort has been made in the preparation of this book to ensure the accuracy of the information presented. However, the information contained in this book is sold without warranty, either express or implied. Neither the author, nor Packt Publishing or its dealers and distributors, will be held liable for any damages caused or alleged to have been caused directly or indirectly by this book.
Packt Publishing has endeavored to provide trademark information about all of the companies and products mentioned in this book by the appropriate use of capitals. However, Packt Publishing cannot guarantee the accuracy of this information.
Commissioning Editor: Richa TripathiAcquisition Editor: Karan SadawanaContent Development Editor: Lawrence VeigasTechnical Editor: Adhithya HaridasCopy Editor: Safis EditingProject Coordinator: Prajakta NaikProofreader: Safis EditingIndexer: Rekha NairGraphics: Jisha ChirayilProduction Coordinator: Arvindkumar Gupta
First published: April 2018
Production reference: 1250418
Published by Packt Publishing Ltd. Livery Place 35 Livery Street Birmingham B3 2PB, UK.
ISBN 978-1-78847-543-3
www.packtpub.com
Mapt is an online digital library that gives you full access to over 5,000 books and videos, as well as industry leading tools to help you plan your personal development and advance your career. For more information, please visit our website.
Spend less time learning and more time coding with practical eBooks and Videos from over 4,000 industry professionals
Improve your learning with Skill Plans built especially for you
Get a free eBook or video every month
Mapt is fully searchable
Copy and paste, print, and bookmark content
Did you know that Packt offers eBook versions of every book published, with PDF and ePub files available? You can upgrade to the eBook version at www.PacktPub.com and as a print book customer, you are entitled to a discount on the eBook copy. Get in touch with us at [email protected] for more details.
At www.PacktPub.com, you can also read a collection of free technical articles, sign up for a range of free newsletters, and receive exclusive discounts and offers on Packt books and eBooks.
Piotr Mińkowski has more than 10 years of experience working as a developer and an architect in the banking and telecommunications sectors. He specializes in Java as well as in technologies, tools, and frameworks associated with it. Now, he is working at Play, a mobile operator in Poland, where he is responsible for the IT systems architecture. Here, he helps the organization migrate from monoliths/SOA to a microservices-based architecture, and also helps set up full Continuous Integration and Delivery environments.
Samer ABDELKAFI has over 13 years of experience as a software architect and engineer, with a major focus on open source technologies. He has contributed to numerous and diverse projects in different sectors, such as banking, insurance, education, public services, and utility billing. In the end of 2016, he created DEVACT, a company specializing in information technology consulting. He also reviewed a book titled Spring MVC Blueprints. In addition to his day job, Samer shares his experience in his blog, writing articles related to Java and web technologies.
If you're interested in becoming an author for Packt, please visit authors.packtpub.com and apply today. We have worked with thousands of developers and tech professionals, just like you, to help them share their insight with the global tech community. You can make a general application, apply for a specific hot topic that we are recruiting an author for, or submit your own idea.
Title Page
Copyright and Credits
Mastering Spring Cloud
Packt Upsell
Why subscribe?
PacktPub.com
Contributors
About the author
About the reviewer
Packt is searching for authors like you
Preface
Who this book is for
What this book covers
To get the most out of this book
Download the example code files
Conventions used
Get in touch
Reviews
Introduction to Microservices
The blessings of microservices
Building microservices with Spring Framework
Cloud-native development
Learning the microservices architecture
Understanding the need for service discovery
Communication between services
Failures and circuit breakers
Summary
Spring for Microservices
Introducing Spring Boot
Developing applications with Spring Boot
Customizing configuration files
Creating RESTful Web Services
API Documentation
Using Swagger 2 together with Spring Boot
Testing API with Swagger UI
Spring Boot Actuator features
Application information
Health information
Metrics
Developer tools
Integrating application with database
Building a sample application
Running the application
Summary
Spring Cloud Overview
Beginning with the basics
Netflix OSS
Service discovery with Eureka
Routing with Zuul
Load balancing with Ribbon
Writing Java HTTP clients
Latency and fault tolerance with Hystrix
Configuration management with Archaius
Discovery and distributed configuration
An alternative – Consul
Apache Zookeeper
Miscellaneous projects
Distributed tracing with Sleuth
Messaging and integration
Cloud platform support
Other useful libraries
Security
Automated testing
Cluster features
Projects overview 
Release trains
Summary
Service Discovery
Running Eureka on the server side
Enabling Eureka on the client side
Deregistration on shutdown
Using discovery client programmatically
Advanced configuration settings
Refreshing the registry
Changing the instance identificator 
Preferring the IP address
Response cache
Enabling secure communication between client and server
Registering a secure service
Eureka API
Replication and high availability
Architecture of the sample solution
Building the example application
Failover
Zones
Zones with a standalone server
Building an example application
Summary
Distributed Configuration with Spring Cloud Config
Introduction to HTTP API resources
Native profile support
Building a server-side application
Building a client-side application
Adding a Eureka Server
Client-side bootstrap approaches
Config Server discovery
Repository backend types
Filesystem backend
Git backend
Different protocols
Using placeholders in URIs
Building a server application
Client-side configuration
Multiple repositories
Vault backend
Getting started with Vault
Integration with Spring Cloud Config
Client-side configuration
Additional features
Fail on start and retry
Secure client
Reload configuration automatically
Solution architecture
Reload configuration with @RefreshScope
Consuming events from a message broker
Monitoring repository changes on a Config Server
Simulating change events manually
Testing locally with a GitLab instance 
Summary
Communication Between Microservices
Different styles of communication 
Synchronous communication with Spring Cloud
Load balancing with Ribbon
Enabling communication between microservices using the Ribbon client
Static load balancing configuration
Calling other services
Using RestTemplate together with service discovery
Building example application
Using Feign client
Support for different zones
Enabling Feign for an application
Building Feign interfaces
Launching microservices
Inheritance support
Creating a client manually
Client customization
Summary
Advanced Load Balancing and Circuit Breakers
Load balancing rules
The WeightedResponseTime rule
Introducing Hoverfly for testing
Testing the rule
Customizing the Ribbon client
The circuit breaker pattern with Hystrix
Building an application with Hystrix
Implementing Hystrix's commands
Implementing fallback with cached data
The tripping circuit breaker
Monitoring latency and fault tolerance
Exposing Hystrix's metrics stream
Hystrix dashboard
Building an application with the dashboard
Monitoring metrics on the dashboard
Aggregating Hystrix's streams with Turbine
Enabling Turbine
Enabling Turbine with streaming
Failures and the circuit breaker pattern with Feign
Retrying the connection with Ribbon
Hystrix's support for Feign
Summary
Routing and Filtering with API Gateway
Using Spring Cloud Netflix Zuul
Building a gateway application
Integration with service discovery
Customizing route configuration
Ignoring registered services
Explicity set service name 
Route definition with the Ribbon client
Adding a prefix to the path
Connection settings and timeouts
Secure headers
Management endpoints
Providing Hystrix fallback
Zuul filters
Predefined filters
Custom implementations
Using Spring Cloud Gateway
Enable Spring Cloud Gateway for a project
Built-in predicates and filters
Gateway for microservices
Integration with service discovery
Summary
Distributed Logging and Tracing
Best logging practices for microservices
Logging with Spring Boot
Centralizing logs with ELK Stack
Setting up ELK Stack on the machine
Integrating an application with ELK Stack
Using LogstashTCPAppender
Using AMQP appender and a message broker
Spring Cloud Sleuth
Integrating Sleuth with an application
Searching events using Kibana
Integrating Sleuth with Zipkin
Running the Zipkin server
Building the client application
Analyze data with the Zipkin UI
Integration via message broker
Summary
Additional Configuration and Discovery Features
Using Spring Cloud Consul
Running Consul agent
Integration on the client side
Service discovery
Health check
Zones
Client settings customization
Running in clustered mode
Distributed configuration
Managing properties in Consul
Client customization
Watching configuration changes
Using Spring Cloud Zookeeper
Running Zookeeper
Service discovery
Client implementation
Zookeeper dependencies
Distributed configuration
Summary
Message-Driven Microservices
Learning about Spring Cloud Stream
Building a messaging system
Enabling Spring Cloud Stream
Declaring and binding channels
Customizing connectivity with the RabbitMQ broker
Integration with other Spring Cloud projects
The publish/subscribe model
Running a sample system
Scaling and grouping
Running multiple instances
Consumer groups
Partitioning
Configuration options
Spring Cloud Stream properties
Binding properties
The consumer
The producer
The advanced programming model
Producing messages
Transformation
Consuming messages conditionally
Using Apache Kafka
Running Kafka
Customizing application settings
Kafka Streams API support
Configuration properties
Multiple binders
Summary
Securing an API
Enabling HTTPS for Spring Boot
Secure discovery
Registering a secure application
Serving Eureka over HTTPS
Keystore generation
Configurating SSL for microservices and Eureka server
Secure configuration server
Encryption and decryption
Configuring authentication for a client and a server
Authorization with OAuth2
Introduction to OAuth2
Building an authorization server
Client configuration
Using the JDBC backend store
Inter-service authorization
Enabling SSO on the API gateway
Summary
Testing Java Microservices
Testing strategies
Testing Spring Boot applications
Building the sample application
Integration with the database
Unit tests
Component tests
Running tests with an in-memory database
Handling HTTP clients and service discovery
Implementing sample tests
Integration tests
Categorizing tests
Capturing HTTP traffic
Contract tests
Using Pact
Consumer side
Producer side
Using Spring Cloud Contract
Defining contracts and generating stubs
Verifying a contract on the consumer side
Scenarios
Performance testing
Gatling
Enabling Gatling
Defining the test scenario
Running a test scenario
Summary
Docker Support
Introducing Docker
Installing Docker
Commonly used Docker commands
Running and stopping a container
Listing and removing containers
Pulling and pushing images
Building an image
Networking
Creating a Docker image with microservices
Dockerfiles
Running containerized microservices
Building an image using the Maven plugin
Advanced Docker images
Continuous Delivery
Integrating Jenkins with Docker
Building pipelines
Working with Kubernetes
Concepts and components
Running Kubernetes locally via Minikube
Deploying an application
Maintaining a cluster
Summary
Spring Microservices on Cloud Platforms
Pivotal Cloud Foundry
Usage models
Preparing the application
Deploying the application
Using CLI
Binding to services
Using the Maven plugin
Maintenance
Accessing deployment details
Managing application life cycles
Scaling
Provisioning brokered services
The Heroku platform
Deployment methods
Using the CLI
Connecting to the GitHub repository
Docker Container Registry
Preparing an application
Testing deployments
Summary
Other Books You May Enjoy
Leave a review - let other readers know what you think
Developing, deploying, and operating cloud applications should be as easy as local applications. This should be the governing principle behind any cloud platform, library, or tool. Spring Cloud makes it easy to develop JVM applications for the cloud. In this book, we introduce you to Spring Cloud and help you master its features.
You will learn to configure the Spring Cloud server and run the Eureka server to enable service registration and discovery. Then you will learn about techniques related to load balancing and circuit breaking and utilize all the features of the Feign client. We then dive into advanced topics where you will learn to implement distributed tracing solutions for Spring Cloud and build message-driven microservice architectures.
This book appeals to developers keen to take advantage of Spring Cloud, an open source library which helps developers quickly build distributed systems. Knowledge of Java and Spring Framework will be helpful, but no prior exposure to Spring Cloud is required.
Chapter 1, Introduction to Microservices, will introduce you to the microservices architecture, cloud environment, etc. You will learn the difference between a microservice based application and a monolith application while also learning how to migrate to a microservices application.
Chapter 2, Spring for Microservices, will introduce you Spring Boot framework. You will learn how to effictively use it to create microservice application. We will cover such topics like creating REST API using Spring MVC annotations, providing API documentation using Swagger2, and exposing health checks and metrics using Spring Boot Actuator endpoints.
Chapter 3, Spring Cloud Overview, will provide a short description of the main projects being a part of Spring Cloud. It will focus on describing the main patterns implemented by Spring Cloud and assigning them to the particular projects.
Chapter 4, Service Discovery, will describe a service discovery pattern with Spring Cloud Netflix Eureka. You will learn how to run Eureka server in standalone mode and how to run multiple server instances with peer-to-peer replication. You will also learn how to enable discovery on the client side and register these clients in different zones.
Chapter 5, Distributed Configuration with Spring Cloud Config, will describe how use distributed configuration with Spring Cloud Config in your applications. You will learn how to enable different backend repositories of property sources and push change notifications using Spring Cloud Bus. We will compare discovery first bootstrap and config first bootstrap approaches to illustrate integration between discovery service and configuration server.
Chapter 6, Communication Between Microservices, will describe the most important elements taking a part in an inter-service communication: HTTP clients and load balancers. You will learn how to use Spring RestTemplate, Ribbon, and Feign clients with or without service discovery.
Chapter 7, Advanced Load Balancing and Circuit Breakers, will described more advanced topics related to inter-service communication between microservices. You will learn how to implement different load balancing algorithms with Ribbon client, enabling circuit breaker pattern using Hystrix and using Hystrix dashboard to monitor communication statistics.
Chapter 8, Routing and Filtering with API Gateway, will compare two projects used as an API gateway and proxy for Spring Cloud applications: Spring Cloud Netlix Zuul and Spring Cloud Gateway. You will learn how to integrate them with service discovery and create simple and more advanced routing and filtering rules.
Chapter 9, Distributed Logging and Tracing, will introduce some popular tools for collecting and analizing logging and tracing information generated by microservices. You will learn how to use Spring Cloud Sleuth to append tracing information and correlating messages. We will run sample applications that integrates with Elastic Stack in order to sent there log messages, and Zipkin to collect traces.
Chapter 10, Additional Configuration and Discovery Features, will introduce two popular products used for service discovery and distributed configuration: Consul and ZooKeeper. You will learn how to run these tools locally, and intergrate your Spring Cloud applications with them.
Chapter 11, Message-Driven Microservices, will guide you how to provide asynchronous, message-driven communication between your microservices. You will learn how to integrate RabbitMQ and Apache Kafka message brokers with your Spring Cloud application to enable asynchronous one-to-one and publish/subscribe communication styles.
Chapter 12, Securing an API, will describe varius ways of securing your microservices. We will implement a system consisting of all previously introduced elements, that communicates with each other over SSL. You will also learn how to use OAuth2 and JWT token to authorize requests coming to your API.
Chapter 13, Testing Java Microservices, will describe different strategies of microservices testing. It will focus on showing consumer-driven contract tests, especially useful in microservice-based environment. You will how to use such frameworks like Hoverfly, Pact, Spring Cloud Contract, Gatling for implemnting different types of automated tests.
Chapter 14, Docker Support, will provide a short introduction to Docker. It will focus on describing most commonly used Docker commands, which are used for running and monitoring microservices in containerized environment. You will also learn how to build and run containers using popular continuous integration server - Jenkins, and deploy them on Kubernetes platform.
Chapter 15, Spring Microservices on Cloud Platforms, will introduce two popular cloud platforms that support Java applications: Pivotal Cloud Foundry and Heroku. You will learn how to deploy, start, scale and monitor your applications on these platforms using command-line tools or web console.
In order to successfully read through this book and work out all the code samples, we expect readers to fulfill the following requirements:
An active internet connection
Java 8+
Docker
Maven
Git client
You can download the example code files for this book from your account at www.packtpub.com. If you purchased this book elsewhere, you can visit www.packtpub.com/support and register to have the files emailed directly to you.
You can download the code files by following these steps:
Log in or register at
www.packtpub.com
.
Select the
SUPPORT
tab.
Click on
Code Downloads & Errata
.
Enter the name of the book in the
Search
box and follow the onscreen instructions.
Once the file is downloaded, please make sure that you unzip or extract the folder using the latest version of:
WinRAR/7-Zip for Windows
Zipeg/iZip/UnRarX for Mac
7-Zip/PeaZip for Linux
The code bundle for the book is also hosted on GitHub athttps://github.com/PacktPublishing/Mastering-Spring-Cloud. We also have other code bundles from our rich catalog of books and videos available athttps://github.com/PacktPublishing/. Check them out!
There are a number of text conventions used throughout this book.
CodeInText: Indicates code words in text, database table names, folder names, filenames, file extensions, pathnames, dummy URLs, user input, and Twitter handles. Here is an example: "The last available version of the HTTP API endpoint, http://localhost:8889/client-service-zone3.yml, returns data identical to the input file."
A block of code is set as follows:
<dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-config-server</artifactId></dependency>
When we wish to draw your attention to a particular part of a code block, the relevant lines or items are set in bold:
spring:
rabbitmq:
host: 192.168.99.100 port: 5672
Any command-line input or output is written as follows:
$ curl -H "X-Vault-Token: client" -X GET http://192.168.99.100:8200/v1/secret/client-service
Bold: Indicates a new term, an important word, or words that you see onscreen. For example, words in menus or dialog boxes appear in the text like this. Here is an example: "In Google Chrome, you can import a PKCS12 keystore by going to section Settings | Show advanced settings... | HTTPS/SSL | Manage certificates."
Feedback from our readers is always welcome.
General feedback: Email [email protected] and mention the book title in the subject of your message. If you have questions about any aspect of this book, please email us at [email protected].
Errata: Although we have taken every care to ensure the accuracy of our content, mistakes do happen. If you have found a mistake in this book, we would be grateful if you would report this to us. Please visit www.packtpub.com/submit-errata, selecting your book, clicking on the Errata Submission Form link, and entering the details.
Piracy: If you come across any illegal copies of our works in any form on the Internet, we would be grateful if you would provide us with the location address or website name. Please contact us at [email protected] with a link to the material.
If you are interested in becoming an author: If there is a topic that you have expertise in and you are interested in either writing or contributing to a book, please visit authors.packtpub.com.
Please leave a review. Once you have read and used this book, why not leave a review on the site that you purchased it from? Potential readers can then see and use your unbiased opinion to make purchase decisions, we at Packt can understand what you think about our products, and our authors can see your feedback on their book. Thank you!
For more information about Packt, please visit packtpub.com.
Microservices are one of the hottest trends to emerge in the IT world during the last few years. It is relatively easy to identify the most important reasons for their growing popularity. Both their advantages and disadvantages are well known, although what we describe as disadvantages can be easily solved using the right tools. The advantages that they offer include scalability, flexibility, and independent delivery; these are the reasons for its rapidly growing popularity. There are a few earlier IT trends that had some influence over this growth in the popularity of microservices. I'm referring to trends such as the usage of common cloud-based environments and the migration from relational databases to NoSQL.
Before discussing this at length, let's see the topics we will cover in this chapter:
Cloud-native development with Spring Cloud
The most important elements in microservices-based architecture
Models of interservice communication
Introduction to circuit breakers and fallback patterns
The concept of microservices defines an approach to the architecture of IT systems that divides an application into a collection of loosely coupled services that implement business requirements. In fact, this is a variant of the concept of service-oriented architecture (SOA). One of the most important benefits of a migration to microservices-based architecture is an ability to perform continuous delivery of large and complex applications.
By now, you have probably had an opportunity to read some books or articles about microservices. I think that most of them would have given you a detailed description of their advantages and drawbacks. There are many advantages to using microservices. The first is that microservices are relatively small and easy to understand for a new developer in a project. We usually want to make sure that the change in the code performed in one place would not have an unwanted effect on all the other modules of our application. With microservices, we can have more certainty about this because we implement only a single business area, unlike monolithic applications where sometimes even seemingly unrelated functionalities are put in the same boat. That is not all. I have noticed that, usually, it is easier to maintain expected code quality in small microservices than in a large monolith where many developers have introduced their changes.
The second thing I like about microservices architecture concerns division. Until now, when I had to deal with complex enterprise systems, I always saw that dividing the system into subsystems was done according to other subsystems. For example, telecommunication organizations always have a billing subsystem. Then you create a subsystem that hides the billing complexity and provides an API. Then you find out that you need data that can't be stored in the billing system because it is not easily customizable. So you create another subsystem. This leads in effect to you building a complicated subsystem mesh, which is not easy to understand, especially if you are a new employee in the organization. With microservices, you do not have problems such as this. If they are well-designed, every microservice should be responsible for an entire selected area. In some cases, those areas are similar regardless of the sector in which an organization is active.
Although the concept of microservices has been an important topic for some years, there are still not many stable frameworks that support all the features needed to run full microservices environments. Since the beginning of my adventure with microservices, I have been trying to keep up with the latest frameworks and find out the features developed towards the needs of microservices. There are some other interesting solutions, such as Vert.x or Apache Camel, but none of them is a match for Spring Framework.
Spring Cloud implements all proven patterns that are used in microservice-based architecture, such as service registries, the configuration server, circuit breakers, cloud buses, OAuth2 patterns, and API gateways. It has a strong community, therefore new features are released at a high frequency. It is based on Spring's open programming model used by millions of Java developers worldwide. It is also well-documented. You won't have any problems in finding many available examples of Spring Framework usage online.
Microservices are intrinsically linked to cloud-computing platforms, but the actual concept of microservices is nothing new. This approach has been applied in the IT development world for many years, but now, through the popularity of cloud solutions, it has evolved to a higher level. It is not hard to point out the reasons for this popularity. The use of a cloud offers you scalability, reliability, and low maintenance costs in comparison with on-premises solutions inside the organization. This has led to the rise of cloud-native application development approaches that are intended to give you the benefits from all of the advantages offered by cloud-like elastic scaling, immutable deployments, and disposable instances. It all comes down to one thing—decreasing the time and cost that is needed to meet new requirements. Today, software systems and applications are being improved continuously. If you have a traditional approach to development, based on monoliths, a code base grows and becomes too complex for modifications and maintenance. Introducing new features, frameworks, and technologies becomes hard, which in turn impacts innovations and inhibits new ideas. We can't argue with that.
There is also another side to this coin. Today, practically everyone thinks about migration to the cloud, partly because it's trendy. Does everyone need this? Certainly not. Those who are not absolutely sure about migrating their applications to a remote cloud provider, such as AWS, Azure, or Google, would like to at least have an on-premises private cloud or Docker containers. But will it really bring them the benefits that compensate for expenses incurred? It is worth answering that question before looking at cloud-native development and cloud platforms.
I'm not trying to dissuade you from using Spring Cloud—quite the opposite. We have to thoroughly understand what cloud-native development is. Here is a really fine definition:
Spring is designed to accelerate your cloud-native development. Building an application with Spring Boot is very quick; I'll show you how to do this in detail in the next chapter. Spring Cloud implements microservice architecture patterns and helps us in using the most popular solutions from that field. Applications developed using these frameworks can easily be adapted to be deployed on Pivotal Cloud Foundry or Docker containers, but they might as well be launched in the traditional way as separated processes on one or more machines, and you would have the advantage of a microservices approach. Let's now dive into the microservices architecture.
Let's imagine that a client approaches you, wanting you to design a solution for them. They need some kind of banking application that has to guarantee data consistency within the whole system. Our client had been using an Oracle database until now and has also purchased support from their side. Without thinking too much, we decide to design a monolithic application based on a relational data model. You can see a simplified diagram of the system's design here:
There are four entities that are mapped into the tables in the database:
The first of them,
Customer
, stores and retrieves the list of active clients
Every customer could have one or more accounts, which are operated by the
Account
entity
The
Transfer
entity is responsible for performing all transfers of funds between accounts within the system
There is also the
Product
entity that is created to store information such as the deposits and credits assigned to the clients
Without going into further details, the application exposes the API that provides all the necessary operations for realizing actions on the designed database. Of course, the implementation is in compliance with the three-layer model.
Consistency is not the most important requirement anymore; it is not even obligatory. The client expects a solution, but does not want the development to require the redeployment of the whole application. It should be scalable and should easily be able to extend new modules and functionalities. Additionally, the client does not put pressure on the developer to use Oracle or another relational database—not only that, but he would be happy to avoid using it. Are these sufficient reasons to decide on migrating to microservices? Let's just assume that they are. We divide our monolithic application into four independent microservices, each one of them with a dedicated database. In some cases, it can still be a relational database, while in others it can be a NoSQL database. Now, our system consists of many services that are independently built and run in our environment. Along with an increase in the number of microservices, there is a rising level of system complexity. We would like to hide that complexity from the external API client, which should not be aware that it talks to service X but not Y. The gateway is responsible for dynamically routing all requests to different endpoints. For example, the worddynamicallymeans that it should be based on entries in the service discovery, which I'll talk about later in the section Understanding the need for service discovery.
Hiding invocations of specific services or dynamic routing is not the only function of an API gateway. Since it is the entry point to our system, it can be a great place to track important data, collect metrics of requests, and count other statistics. It can enrich requests or response headers in order to include some additional information that is usable by the applications inside the system. It should perform some security actions, such as authentication and authorization, and should be able to detect the requirements for each resource and reject requests that do not satisfy them. Here's a diagram that illustrates the sample system, consisting of four independent microservices, which is hidden from an external client behind an API gateway:
Let's imagine that we have already divided our monolithic application into smaller, independent services. From the outside, our system still looks the same as before, because its complexity is hidden behind the API gateway. Actually, there are not many microservices, but, there may well be many more. Additionally, each of them can interact with the others. That means that every microservice has to keep information about the others' network addresses. Maintaining such a configuration could be very troublesome, especially when it comes down to manually overwriting every configuration. And what if those addresses are changing dynamically after restart? The following diagram shows the calling routes between our example microservices:
Service discovery is the automatic detection of devices and services offered by these devices on a computer network. In the case of microservice-based architecture, this is the necessary mechanism. Every service after startup should register itself in one central place that is accessible by all other services. The registration key should be the name of a service or an identificator, which has to be unique within the whole system in order to enable others to find and call the service using that name. Every single key with the given name has some values assigned to it. In the most common cases, these attributes indicate the network location of the service. To be more accurate, they indicate one of the instances of the microservice because it can be multiplied as independent applications running on different machines or ports. Sometimes it is possible to send some additional information, but it depends on the concrete service discovery provider. However, the important thing here is that under the one key, more than one instance of the same service may be registered. In addition to registration, each service gets a full list of the other services registered on the particular discovery server. Not only that, every microservice must be aware of any changes in the registration list. This may be achieved by periodically renewing the configuration earlier collected from the remote server.
Some solutions combine the usage of service discovery with the server configuration feature. When it comes right down to it, both approaches are pretty similar. The configuration of the server lets you centralize the management of all configuration files in your system. Usually, such a configuration is then a server as a REST web service. Before startup, every microservice tries to connect to the server and get the parameters prepared especially for it. One of the approaches stores such a configuration in the version control system—for example, Git. Then the configuration server updates its Git working copy and serves all properties as a JSON. In another approach, we can use solutions that store key-value pairs and fulfill the role of providers during the service discovery procedure. The most popular tools for this are Consul and Zookeeper. The following diagram illustrates an architecture of a system that consists of some microservices with a database backend that are registered in one central service known as a discovery service:
In order to guarantee the system's reliability, we cannot allow a situation where each service would have only one instance running. We usually aim to have a minimum of two running instances in case one of them experiences a failure. Of course, there could be more, but we'll keep it low for performance reasons. Anyway, multiple instances of the same service make it necessary to use load balancing for incoming requests. Firstly, the load balancer is usually built into an API gateway. This load balancer should get the list of registered instances from the discovery server. If there is no reason not to, then we usually use a round-robin rule that balances incoming traffic 50/50 between all running instances. The same rule also applies to load balancers on the microservices side.
The following diagram illustrates the most important components that are involved in interservice communication between multiple instances of two sample microservices:
Most people, when they hear about microservices, consider it to consist of RESTful web services with JSON notation, but that's just one of the possibilities. We can use some other interaction styles, which, of course, apply not only to microservices-based architecture. The first categorization that should be performed is one-to-one or one-to-many communication. In one-to-one interaction, every incoming request is processed by exactly one service instance while, in one-to-many, it is processed by multiple service instances. But the most popular division criterion is whether the call is synchronous or asynchronous. Additionally, asynchronous communication can be divided into notifications. When a client sends a request to a service, but a reply is not expected, it can just perform a simple asynchronous call, which does not block a thread and replies asynchronously.
Furthermore, it is worth mentioning reactive microservices. Now, from version 5, Spring also supports this type of programming. There are also libraries with Reactive support for interaction with NoSQL databases, such as MongoDB or Cassandra. The last well-known communication type is publish-subscribe. This is a one-to-many interaction type where a client publishes a message that is then consumed by all listening services. Typically, this model is realized using message brokers, such as Apache Kafka, RabbitMQ, and ActiveMQ.
We have discussed most of the important concepts related to the microservices architecture. Such mechanisms, such as service discovery, API gateways, and configuration servers, are useful elements that help us to create a reliable and efficient system. Even if you have considered many aspects of these while designing your system's architecture, you should always be prepared for failures. In many cases, the reasons for failures are totally beyond the control of the holder, such as network or database problems. Such errors can be particularly severe for microservice-based systems, where one input request is processed in many subsequent calls. The first good practice is to always use network timeouts when waiting for a response. If a single service has a performance problem, we should try to minimize the impact on the rest. It is better to send an error response than to wait on a reply for a long time, blocking other threads.
An interesting solution for the network timeout problems might be the circuit breaker pattern. It is a concept closely related to the microservice approach. A circuit breaker is responsible for counting successful and failed requests. If the error rate exceeds an assumed threshold, it trips and causes all further attempts to fail immediately. After a specific period of time, the API client should get back to sending requests, and if they succeed, it closes the circuit breaker. If there are many instances of each service available and one of them works slower than others, the result is that it is overlooked during the load balancing process. The second often-used mechanism for dealing with partial network failures is fallback. This is a logic that has to be performed when a request fails. For example, a service can return cached data, a default value, or an empty list of results. Personally, I'm not a big fan of this solution. I would prefer to propagate error code to other systems than return cached data or default values.
The big advantage of Spring Cloud is that it supports all the patterns and mechanisms we have looked at. These are also stable implementations, unlike some other frameworks. I'll describe in detail which of the patterns are supported by which Spring Cloud project inChapter 3,Spring Cloud Overview.
In this chapter, we have discussed the most important concepts related to microservices architecture, such as cloud-native development, service discovery, distributed configuration, API gateways, and the circuit breaker pattern. I have attempted to present my point of view about the advantages and drawbacks of this approach in the development of enterprise applications. Then, I described the main patterns and solutions related to microservices. Some of these are well-known patterns that have been around for years and are treated as something new in the IT world. In this summary, I would like to turn your attention to some things. Microservices are cloud-native by their nature. Frameworks such as Spring Boot and Spring Cloud help you to accelerate your cloud-native development. The main motivation of migrating to cloud-native development is the ability to implement and deliver applications faster while maintaining high quality. In many cases, microservices help us to achieve this, but sometimes the monolithic approach is not a bad choice.
Although microservices are small and independent units, they are managed centrally. Information such as network location, configuration, logging files, and metrics should be stored in one central place. There are various types of tools and solutions that provide all these features. We will talk about them in detail in almost all of the chapters in this book. The Spring Cloud project is designed to help us in integrating with all that stuff. I hope to efficiently guide you through the most important integrations it offers.
I don't know many Java developers who have never touched Spring Framework. Actually, it consists of so many projects and can be used with many other frameworks that sooner or later you will be forced to try it. Although experiences with Spring Boot are rather less common, it has quickly gained a lot of popularity. In comparison with Spring Framework, Spring Boot is a relatively new solution. Its actual version is 2, instead of 5 for Spring Framework. What was the purpose of its creation? What is the difference between a running application with Spring Boot instead of the standard Spring Framework way?
Topics we will cover in this chapter include:
Using starters in order to enable additional features for the project
Using Spring Web library for implementing services that expose REST API methods
Customizing service configuration using properties and YAML files
Documenting and providing the specification for exposed REST endpoints
Configuring health checks and monitoring features
Using Spring Boot profiles to adapt the application to run in different modes
Using ORM features for interacting with embedded and remote NoSQL databases
Spring Boot is dedicated to running standalone Spring applications, the same as simple Java applications, with the java -jar command. The basic thing that makes Spring Boot different than standard Spring configuration is simplicity. This simplicity is closely related to the first important term we need to know about, which is a starter. A starter is an artifact that can be included in the project dependencies. It does nothing more than provide a set of dependencies to other artifacts that have to be included in your application in order to achieve the desired functionality. A package delivered in that way is ready for use, which means that we don't have to configure anything to make it work. And that brings us to the second important term related to Spring Boot, auto-configuration. All artifacts included by the starters have default settings set, which can be easily overridden using properties or other types of starters. For example, if you include spring-boot-starter-web in your application dependencies it embeds a default web container and starts it on the default port during application startup. Looking forward, the default web container in Spring Boot is Tomcat, which starts on port 8080. We can easily change this port by declaring the specified field in the application properties file and even change the web container by includingspring-boot-starter-jettyorspring-boot-starter-undertow in our project dependencies.
Let me say a few words more about starters. Their official naming pattern is spring-boot-starter-*, where * is the particular type of starter. There are plenty of starters available within Spring Boot, but I would like to give you a short briefing on the most popular of them, which have also been used in the examples provided in the following chapters of this book:
Name
Description
spring-boot-starter
Core starter, including auto-configuration support, logging, and YAML.
spring-boot-starter-web
Allows us to build web applications, including RESTful and Spring MVC. Uses Tomcat as the default embedded container.
spring-boot-starter-jetty
Includes Jetty in the project and sets it as the default embedded servlet container.
spring-boot-starter-undertow
Includes Undertow in the project and sets it as the default embedded servlet container.
spring-boot-starter-tomcat
Includes Tomcat as the embedded servlet container. The default servlet container starter used by
spring-boot-starter-web
.
spring-boot-starter-actuator
Includes
Spring Boot Actuator in the project, which provides features for monitoring and managing applications.
spring-boot-starter-jdbc
Includes Spring JBDC with the Tomcat connection pool. The driver for the specific database should be provided by yourself.
spring-boot-starter-data-jpa
Includes
all artifacts needed for interaction with relational databases using JPA/Hibernate.
spring-boot-starter-data-mongodb
Includes
all artifacts needed for interaction with MongoDB and initializing a client connection to Mongo on localhost.
spring-boot-starter-security
Includes
Spring Security in the project and enables basic security for applications by default.
spring-boot-starter-test
Allows the creation of unit tests using such libraries as JUnit, Hamcrest, and Mockito.
spring-boot-starter-amqp
Includes
Spring AMQP to the project and starts RabbitMQ as the default AMQP broker.
If you are interested in the full list of available starters, refer to the Spring Boot specification. Now, let's get back to the main differences between Spring Boot and standard configuration with Spring Framework. Like I mentioned before we can include spring-boot-starter-web, which embeds a web container into our application. With standard Spring configuration, we do not embed a web container into the application, but deploy it as a WAR file on the web container. This is a key difference and one of the most important reasons that Spring Boot is used for creating applications deployed inside microservice architecture. One of the main features of microservices is independence from other microservices. In this case, it is clear that they should not share common resources, such as databases or web containers. Deploying many WAR files on one web container is an anti-pattern for microservices. Spring Boot is, therefore, the obvious choice.
Personally, I have used Spring Boot while developing many applications, not only when working in a microservice environment. If you try it instead of standard Spring Framework configuration, you will not want to go back. In support of that conclusion you can find an interesting diagram that illustrates the popularity of Java frameworks repositories on GitHub: http://redmonk.com/fryan/files/2017/06/java-tier1-relbar-20170622-logo.png. Let's take a closer look at how to develop applications with Spring Boot.
The recommended way to enable Spring Boot in your project is by using a dependency management system. Here, you can see a short snippet of how to include appropriate artifacts in your Maven and Gradle projects. Here is a sample fragment from the Maven pom.xml:
<parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>1.5.7.RELEASE</version></parent><dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency></dependencies>
With Gradle, we do not need to define parent dependency. Here's a fragment from build.gradle:
plugins { id 'org.springframework.boot' version '1.5.7.RELEASE'}dependencies { compile("org.springframework.boot:spring-boot-starter-web:1.5.7.RELEASE")}
When using Maven, it is not necessary to inherit from the spring-boot-starter-parent POM. Alternatively, we can use the dependency management mechanism:
<dependencyManagement> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-dependencies</artifactId> <version>1.5.7.RELEASE</version> <type>pom</type> <scope>import</scope> </dependency> </dependencies></dependencyManagement>
Now, all we need is to create the main application class and annotate it with @SpringBootApplication, which is an equivalent to three other annotations used together—@Configuration, @EnableAutoConfiguration, and @ComponentScan:
@SpringBootApplicationpublic class Application { public static void main(String[] args) { SpringApplication.run(Application.class, args); }}
Once we have the main class declared and spring-boot-starter-web included, we only need to run our first application. If you use a development IDE, such as Eclipse or IntelliJ, you should just run your main class. Otherwise, the application has to be built and run like a standard Java application with the java -jar command. First, we should provide the configuration that is responsible for packaging all dependencies into an executable JAR (sometimes called fat JARs) during application build. This action would be performed by spring-boot-maven-plugin if it is defined in the Maven pom.xml:
<build>
<plugins>
<plugin>
<groupId>
org.springframework.boot
</groupId>
<artifactId>
spring-boot-maven-plugin
</artifactId>
</plugin>
</plugins>
</build>
The sample application does nothing more than start a Spring context on the Tomcat container, which is available on port 8080. The fat JAR is about 14 MB in size. You can easily, using an IDE, check out which libraries are included in the project. These are all basic Spring libraries, such as spring-core,spring-aop, spring-context; Spring Boot; Tomcat embedded; libraries for logging including Logback, Log4j, and Slf4j; and Jackson libraries used for JSON serialization or deserialization. A good idea is to set the default Java version for the project. You can easily set it up inpom.xmlby declaring thejava.versionproperty:
<properties>
<java.version>
1.8
</java.version>
</properties>
We can change the default web container just by adding a new dependency, for example, to the Jetty server:
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-jetty</artifactId> </dependency>
