• Learn the key features of microservices

  • See how microservices fit into the cloud architecture

  • Decompose the business domain into a set of microservices

  • Implement simple microservices using Spring Boot

  • Grasp the perspective of building applications based on microservices architecture

  • Learn when not to use microservices



The history of software development is littered with stories of huge development projects crashing — projects that invested millions of dollars, concentrated many of the industry’s top talent, consumed thousands of developer man-hours, never delivered anything of value to the customer, and eventually collapsed due to their complexity and burden.

These large projects tend to follow a large traditional waterfall development approach, insisting that all requirements and design of the application be defined at the beginning of the project. Developers on these projects place a high value on “correctness” of software specifications, but are rarely able to meet new business requirements, refactor, and re-think and learn from early development mistakes.

But the reality is that software development is not a linear process of definition and execution, but rather an evolutionary process that requires several iterations of communication, learning, and delivery to the customer before the development team truly understands the problem at hand.

The challenge with the traditional waterfall approach is that many times these projects deliver software artifacts with the following granularity.

  • Tightly coupled — invocation of business logic occurs at the programming language level, rather than through implementation-neutral protocols such as SOAP and REST. This greatly increases the chances that even small changes to an application component can break other parts of the application and introduce new vulnerabilities.

  • Buggy – Most large software applications manage different types of data. For example, a customer relationship management (CRM) application might manage customer, sales, and product information. In the traditional model, this data resides in the same data model and is stored in the same data store. Even when there are clear boundaries between data, in the vast majority of cases, it is easy for teams from one domain to directly access data belonging to another. This easy access to data introduces hidden dependencies and lets implementation details of a component’s internal data structure leak throughout the application. Changes to even a single database table may require extensive code changes and regression testing across the entire application.

  • Singleton — Since most components of a traditional application reside in a single code base shared by multiple teams, any time the code changes, the entire application must be recompiled, re-run, and go through a full test cycle and redeployed. Whether it’s new customer requirements or bug fixes, small changes to an application code base can become expensive and time consuming, and it’s nearly impossible to implement large-scale changes in a timely manner.

Microservices-based architectures take a different approach to delivering functionality. Specifically, the microservices-based architecture has the following characteristics.

  • Constrained — Microservices have a single set of responsibilities with a limited scope. Microservices follow the UNIX philosophy that an application is a collection of services, each of which does one thing and does one thing well.

  • Loosely coupled — Microservices-based applications are collections of small services that interact with each other via non-implementation-specific interfaces using non-proprietary invocation protocols, such as HTTP and REST. Compared to traditional application architectures, owners of microservices have more freedom to modify their services as long as their interfaces remain unchanged.

  • Abstract – Microservices fully own their own data structures and data sources. Data owned by a microservice can only be modified by the service. Database access control that locks microservice data and allows only that service to access it.

  • Standalone — Each microservice in a microservice application can be compiled and deployed independently of other services used in the application. This means that it is easier to isolate and test changes this way than relying on heavier monolithic applications.

Why are these microservice architecture attributes important for cloud-based development? Cloud-based applications typically have the following characteristics.

  • Have a large and diverse user base — different customers need different features, and they don’t want to wait for a long application release cycle before they start using them. Microservices allow for rapid delivery of functionality because each service is small in scope and accessed through a well-defined interface.

  • Extremely high runtime requirements – Due to the decentralized nature of microservices, microservices-based applications can more easily isolate failures and problems to specific parts of the application without crashing the entire application. This reduces the overall downtime of applications and makes them more resilient to problems.

  • Uneven capacity requirements — Traditional applications deployed within an enterprise data center typically have consistent usage patterns that periodically emerge over time, making capacity planning for this type of application simple. But in a cloud-based application, a simple tweet on Twitter or an article on Slashdot can drive a lot of demand for cloud-based applications.

  • Because microservice applications are broken down into components that can be deployed independently of each other, it is easier to focus on components that are under high load and scale them horizontally across multiple servers in the cloud.

The content of this article covers the basics of building and identifying microservices in business problems, building the skeleton of microservices, and then understanding the operational properties of successfully deploying and managing microservices in a production environment. If you want to learn more, please read Spring Micro Services in Action.

To successfully design and build microservices, developers need to approach them like police officers questioning witnesses about criminal activity. Even if each witness saw the same event take place, their interpretation of the crime was shaped by their background, what they valued (for example, what motivated them), and the environmental pressures of witnessing the event at that moment. Each participant has their own perspective (and bias) that they think is important.

Like a successful police officer trying to get to the truth, the process of building a successful microservices architecture requires combining the perspectives of multiple individuals within a software development organization. While it takes more than just technical people to deliver an entire application, I believe that the foundation of successful microservice development starts from the perspective of three key actors.

  • Architect — It is the architect’s job to see the big picture and understand how applications decompose into individual microservices and how microservices interact to deliver solutions.

  • Software developers – Software developers write code and understand in detail how the programming language and its development framework are used to deliver microservices.

  • DevOps Engineers – DevOps engineers provide the intelligence to deploy and manage services not only for production environments but for all non-production environments. The mantra of DevOps engineers is: Consistency and repeatability in every environment.

This article demonstrates how to design and build a set of microservices using Spring Boot and Java from the perspective of these roles. By the end of this article, the reader will have a service that can be packaged and deployed to the cloud.

1.1 Architect’s Story: Designing microservices Architecture

The role of the architect in a software project is to provide a working model of the problem to be solved. The architect’s job is to provide the scaffolding upon which developers will build their code to keep all the parts of the application together.

When building the microservices architecture, the project architect focused on three key tasks:

(1) Decomposition of business problems;

(2) Establish service granularity;

(3) Define the service interface.

1.1.1 Decomposing service problems

Faced with complexity, most people try to break down the problems they are working on into manageable chunks. Because then they don’t have to try to include all the details of the problem. They abstractly break the problem down into several key parts and then look for the relationships that exist between those parts.

In microservices architecture, architects decompose business problems into chunks that represent discrete areas of activity. These blocks encapsulate the business rules and data logic associated with specific parts of the business domain.

Although we want microservices to encapsulate all the business rules that perform a single transaction, this is not always feasible. We often encounter situations where a set of microservices across different parts of the business domain are required to complete the entire transaction. The architect demarcates the service boundaries of a set of microservices by looking at areas of the data domain that do not fit together.

For example, an architect might look at the business processes that the code executes and realize that they require both customer and product information. When there are two discrete data domains, this usually means that multiple microservices need to be used. How two different parts of a business transaction interact is often the service interface for microservices.

Separating business areas is an art, not a black and white science. Readers can use the following guidelines to identify and decompose business problems into alternative microservices.

(1) Describe the business problem and listen to the nouns used to describe the problem. The repeated use of the same term when describing problems usually implies that they are core business areas and suitable for creating microservices. The target nouns for the EagleEye field in Chapter 1 might be contracts, licenses, and assets.

(2) Pay attention to verbs. Verbs highlight the action and usually represent the natural contours of the problem domain. If you find yourself saying things like “Transaction X needs to get data from thing A and thing B,” it’s usually A sign that multiple services are working. If you apply the notice verb approach to EagleEye, you might look for something like “When Mike from Desktop Services installs a new PC, he looks for the number of licenses available for software X, and if there are licenses, installs the software. He then updates statements like “Track the number of licenses used in the spreadsheet.” The key verbs here are to find and update.

(3) Looking for data cohesion. When breaking down a business problem into discrete parts, look for data that is highly correlated with each other. If, in the middle of a session, data is suddenly read or updated that is completely different from what has been discussed so far, there may be other candidate services. Microservices should fully own their own data.

Let’s apply these guidelines to real-world problems. Chapter 1 introduces an existing software product called EagleEye, which is used to manage software assets such as software licenses and secure Socket Layer (SSL) certificates. These software assets are deployed on various servers throughout the organization.

EagleEye is a traditional monolithic Web application deployed on a J2EE application server located in a customer data center. Our goal is to tease apart existing monolithic applications into a set of services.

First, we interview all the users of the EagleEye application and discuss how they interact and use EagleEye. Figure 1-1 depicts a summary of the conversations with different business customers. By looking at how EagleEye’s users interact with the application and how the application’s data model is decomposed, the EagleEye problem domain can be decomposed into the following alternative microservices.

Figure 1-1 highlights some of the nouns and verbs that occur when talking to business users. Because this is an existing application, you can look at the application and map the main nouns to the tables in the physical data model. An existing application may have hundreds of tables, but each table typically maps back to a set of logical entities.

Figure 1-2 shows a simplified data model based on conversations with EagleEye customers. Based on the business dialogue and data model, alternative microservices are organization, license, contract, and asset services.

1.1.2 Establishing service granularity

With a simplified data model, you can begin to define which microservices are required in your application. Based on the data model in Figure 1-2, you can see that the four potential microservices are based on the following elements:

  • Assets;

  • The permit;

  • The contract;

  • Organization.

Our goal is to extract these major features into completely separate units that can be built and deployed independently. However, extracting services from the data model requires more than just repackaging the code into separate projects, it also involves teasing out the actual database tables accessed by the services, and only allowing each individual service to access the tables in its particular domain. Figure 1-3 shows how the application code and data model are “chunked” into parts.

After breaking down the problem domain into different parts, developers often find themselves unsure whether they have the right level of granularity for their services. A microservice that is too coarse-grained or too fine-grained will have many characteristics that we will discuss later.

The issue of granularity is important when building a microservice architecture, and the following ideas can be used to determine the right solution.

(1) Start with a wider range of microservices, and then refactor it into smaller services — one extreme at the beginning of the microservice journey is to make everything microservices. But decomposing the problem domain into small services often leads to premature complexity, as microservices become fine-grained data services.

(2) Focus on how services interact with each other — this helps build coarse-grained interfaces to the problem domain. Refactoring from coarse-grained to fine-grained is relatively easy.

(3) As the understanding of the problem domain grows, the responsibilities of the service will change over time — typically, when new application functionality is required, microservices will take on the responsibilities. The original microservices may evolve into multiple services, and the original microservices act as an orchestration layer for these new services, encapsulating the functionality of other parts of the application.

The “smell” of Bad microservices

How do I know if microservices are correctly classified? If microservices are too coarse-grained, you might see the following.

Services take on too much responsibility — the general flow of business logic in services is complex and seems to be enforcing an overly diverse set of business rules.

The service is managing data across a large number of tables — a microservice is a record system for the data it manages. If you find yourself persisting data to multiple tables or touching tables outside your current database, this is a clue that the service is too coarse-grained. I like to use a guideline that microservices should have no more than 3-5 tables. Any more, and the service may be taking on too much responsibility.

Too many test cases — over time, services grow in size and responsibility. If you start with a service with a few test cases and end up with hundreds of unit and integration test cases, you may need to refactor.

What if microservices are too fine-grained?

Part of the problem domain is that microservices breed like rabbits — if everything becomes microservices, putting together the business logic in the services becomes complicated and difficult because the number of services needed to do a job grows rapidly. A common “bad taste” occurs when an application has dozens of microservices and each service interacts with only one database table.

Microservices are heavily interdependent — in one part of the problem domain, microservices are called back and forth to fulfill a single user request.

Microservices become a collection of simple CRUD (Create, Read, Update, Delete) services — microservices are expressions of business logic rather than abstraction layers for data sources. If microservices do nothing but CRUD-related logic, they may be too fine-grained.

Develop a microservice architecture through an evolutionary process of thinking, where you know you won’t get the design right the first time. This is why it is best to start with a coarse-grained set of services rather than a fine-grained set of services. It’s also important not to be dogmatic about design. When faced with physical constraints such as two separate services interacting too frequently or domains of services not having clear boundaries, an aggregation service needs to be created to connect data together.

Finally, take a pragmatic approach and deliver, rather than waste time trying to make the design perfect and end up with nothing to show for your efforts.

1.1.3 Communication: Define service interfaces

The final part that the architect needs to be concerned with is how the microservices in the application communicate with each other. When building business logic with microservices, the interfaces of the services should be intuitive, and developers should learn about one or two services in the application to get the rhythm of how all the services in the application work.

In general, the following guidelines can be used to think about service interface design.

(1) Embrace REST — REST handles services using HTTP as the invocation protocol for services and using standard HTTP verbs (GET, PUT, POST, and DELETE). The basic behavior is modeled around these HTTP verbs.

(2) Use URIs to communicate intent — URIs used as service endpoints should describe the different resources in the problem domain and provide a basic mechanism for the relationship of resources within the problem domain.

(3) Request and response using JSON — JavaScript Object Notation (JSON) is a very lightweight data serialization protocol and is easier to use than XML.

(4) Use HTTP status codes to convey results – THE HTTP protocol has a rich standard response code to indicate the success or failure of the service. Learn these status codes and, most importantly, use them consistently across all services.

All of these guidelines are intended to accomplish one thing: making the service interface easy to understand and use. We want developers to sit down and look at the service interfaces and start using them. If microservices are not easy to use, developers will go the other way, undermining the intent of the architecture.


Services. By the end of this article, the reader will have a service that can be packaged and deployed to the cloud.

1.2 When not to use microservices

Next, let’s take a look at the factors involved:

(1) The complexity of building distributed systems;

(2) The virtual server/container is scattered;

(3) Type of application;

(4) Data transactions and consistency.

Services. By the end of this article, the reader will have a service that can be packaged and deployed to the cloud.

1.2.1 Complexity of building distributed systems

Because microservices are distributed and fine-grained (small), they introduce a layer of complexity into the application that would not be present in a singleton application. Microservice architectures require a high degree of operational maturity. Don’t consider using microservices unless your organization is willing to invest in the automation and operations (monitoring, scaling) that highly distributed applications need to succeed.

1.2.2 The Server is Scattered

One of the most common deployment patterns for microservices is to deploy a microservice instance on a server. In large microservices-based applications, you can end up with 50 to 100 servers or containers (usually virtual) that must be built and maintained separately. Even with the low cost of running these services in the cloud, the operational complexity of managing and monitoring these servers is enormous.

2.2.3 Types of applications

Microservices are oriented towards reusability and are useful for building large applications that require a high degree of resilience and scalability. That’s one reason so many cloud companies are adopting microservices. If readers are building small, department-level applications or applications with a small user base, the complexity of building a distributed model, such as microservices, may be too expensive to justify.

2.2.4 Data transactions and consistency

When you start looking at microservices, you need to consider the data usage patterns of the services and how the service consumers are using them. Microservices work well by wrapping and abstracting a small number of tables as a mechanism for performing “operational” tasks, such as creating, adding, and executing simple (non-complex) queries against storage.

If your application requires complex data aggregation or transformation across multiple data sources, the distributed nature of microservices can make this difficult. Such microservices always take on too much responsibility and can become vulnerable to performance problems.

Also remember that there are no standards for performing transactions between microservices. If transaction management is required, you need to build your own logic. In addition, as described in Chapter 7, microservices can communicate by using messages. Messaging introduces delays in data updates. Applications need to handle final consistency, and updates to the data may not occur immediately.

1.3 Developer’s Story: Building microservices with Spring Boot and Java

When building microservices, a shift in perspective is required from concept to implementation. Specifically, developers need to establish a basic pattern that implements each microservice in the application. While each service will be unique, we want to ensure that we use a framework that removes boilerplate code and that every part of the microservice has the same layout.

In this section, we explore the priorities of developers building license microservices from the EagleEye domain model. The license service will be written using Spring Boot. Spring Boot is an abstraction layer on top of the standard Spring libraries that allows developers to quickly build Groovy and Java-based Web applications and microservices with significantly less configuration than mature Spring applications.

For the license service example, you will use Java as the core programming language and Apache Maven as the build tool.

In the next few sections, we’ll do the following.

(1) Build the basic framework of microservices and build the Maven script of the application.

(2) Implement a Spring boot class that will launch the Spring container for microservices and initiate all initialization of the class.

(3) Implement a Spring Boot controller class that maps endpoints to expose service endpoints.

1.3.1 Start with skeleton projects

First, create a skeleton project for the license service. Readers can either pull the source code from the GitHub repository for this article or create a license service project directory with the following directory structure:

  • licensing-service

  • src/main/java/com/thoughtmechanix/licenses

  • controllers

  • model

  • services

  • resources

Once the directory structure is pulled or created, you can start writing Maven scripts for your project. This is the pom.xml file located at the root of the project. Listing 1-1 shows the Maven POM file for the license service.

Listing 1-1 Maven POM file for the license service

I won’t go into the whole script in detail here, but there are a few key points to note at the beginning. Spring Boot is broken down into a number of independent projects. The idea is that if you don’t need to use various parts of Spring Boot in your application, you shouldn’t “pull the whole world.” This also enables different Spring Boot projects to release new versions of the code independently. To make development easier for developers, the Spring Boot team collects related dependencies into various starter toolkits. The first part of Maven’s POM tells Maven to pull version 1.4.4 of the Spring Boot framework.

The second and third parts of the Maven file specify pulling Spring Web and Spring Actuator starter kits. These two projects are at the heart of almost all Spring Boot based REST services. The reader will find that the list of these dependencies grows longer the more functionality is built into the service.

In addition, Spring Source provides Maven plug-ins that simplify the building and deployment of Spring Boot applications. The fourth part tells the Maven build script to install the latest Spring Boot Maven plug-in. This plug-in includes a number of additional tasks (such as Spring-Boot: Run) that simplify the interaction between Maven and Spring Boot.

Finally, the reader will see a comment indicating which parts of the Maven file have been removed. For simplicity, the Book does not include the Spotify Docker plug-in in Listing 1-1.

1.3.2 Booting Spring Boot Applications: Write Boot classes

Our goal is to run a simple microservice in Spring Boot and then repeat this step to provide functionality. To do this, we need to create the following two classes in the license Service microservice.

  • A Spring Boot class that can be used by Spring Boot to start and initialize applications.

  • A Spring controller class that exposes HTTP endpoints that can be invoked by microservices.

As you’ve just seen, Spring Boot uses annotations to simplify the setup and configuration of services. This becomes obvious when you look at the bootstrap class in Listing 2-2. This bootstrap class is located in the SRC/main/Java/com/thoughtmechanix/licenses/Application. The Java file.

Code listing 1-2@SpringBootApplication Introduction to annotations

The first thing to notice in this code is the use of @SpringBootApplication. Spring Boot uses this annotation to tell the Spring container that this class is the source of the bean definition used in Spring. In a Spring Boot application, Spring beans can be defined in the following ways.

(1) Annotate a Java class with the @Component, @Service, or @Repository annotation tag.

(2) Annotate a class with the @Configuration annotation tag, and then define a constructor method for each Spring Bean we want to build and add the @Bean tag to the method.

Behind the scenes, the @SpringBootApplication annotation marks the Application class in Listing 2-2 as a configuration class, and then starts automatically scanning all classes on the Java classpath to form additional Spring beans.

The second thing to notice is the main() method of the Application class. In the main() method, the Spring Application.run(application.class, args) call starts the Spring container, A Spring ApplicationContext object is then returned (ApplicationContext is not used to do anything here, so it is not shown in the code.) .

The easiest thing to remember about the @SpringBootApplication annotation and its corresponding Application class is that it is the bootstrap class for the entire microservice. The core initialization logic of the service should be in this class.

1.3.3 Entry point for building microservices: Spring Boot Controller

Now that you have your build script and a simple Spring Boot Boot class implemented, you’re ready to write your first code to do some things. This code is the controller class. In a Spring Boot application, the controller class exposes the service endpoint and maps data from the incoming HTTP request to the Java method that will handle the request.

The first controller class LicenseSerriceController is located in the SRC/main/Java/com/thoughtmechanix/licenses/controllers/LicenseServiceController. In Java. This class exposes four HTTP endpoints that map to the POST, GET, PUT, and DELETE verbs.

Let’s take a look at the controller class and see how Spring Boot provides a set of annotations to ensure that service endpoints are exposed with minimal effort, allowing developers to focus on building the business logic of the service. We’ll start with the basic controller class definition without any class methods. Listing 1-3 shows the controller class built for the license service.

Listing 1-3 marks LicenseServiceController as Spring RestController

Let’s start exploring by looking at the @RestController annotation. RestController is a class-level Java annotation that tells the Spring container that the Java class will be used for a REST-based service. This annotation automatically handles the serialization of data passed to the service as JSON or XML (by default, the @RestController class serializes the returned data to JSON). Unlike the traditional Spring @Controller annotation, the @RestController annotation does not require the developer to return the ResponseBody class from the Controller class. All of this is handled by the @RestController annotation, which contains the @responseBody annotation.

The second annotation shown in Listing 1-3 is @requestMapping. You can use @RequestMapping for class-level annotations and method-level annotations. The @requestMapping annotation is used to tell the Spring container which HTTP endpoints the service will expose. When using the class-level @RequestMapping annotation, the root of the URL is established for all other endpoints exposed by the controller.

In Listing 1-3, @RequestMapping(value=”/v1/ Organizations /{organizationId}/licenses “) uses the value attribute to establish the root of the URL for all endpoints exposed in the controller class. All service endpoints exposed in this controller will root with /v1/ Organizations /{organizationId}/licenses as their endpoints. {organizationId} is a placeholder indicating how to parameterize the URL with the organizationId passed in each call. Using organizationId in the URL differentiates between different customers using the service.

We will now add the first method of the controller. This method implements the GET verb in the REST call and returns a single instance of the License class, as shown in Listing 1-4 (a Java class named License is instantiated for the sake of argument).

Listing 1-4 exposes a GET HTTP endpoint

The first thing done in this code listing is to mark the getLicenses() method with the method-level @RequestMapping annotation, passing two parameters to the annotation, value and method. Using the method-level @Request Mapping annotation, combined with the root-level annotation specified at the top of the class, We matched all HTTP requests coming into the controller with endpoint /v1/organizations/{organizationId}/ forum /{licensedId}. The second argument to the annotation, method, specifies the HTTP verb that the method will match. In the previous example, the GET method is matched in the form of a requestMethod.get enumeration.

The second thing to notice about Listing 1-4 is that the @pathvariable annotation is used in the parameter body of the getLicenses() method. The @pathVariable annotation is used to map parameter values (represented by the {parameterName} syntax) passed in the incoming URL to method parameters. In the example code shown in Listing 1-4, map two parameters organizationId and licenseId to two parameter level variables in the method:

Now, we can call what we just created a service. From the command line window, go to the project directory where you downloaded the sample code, and then execute the following Maven command:

Once you press Enter, you should see Spring Boot start an embedded Tomcat server and start listening on port 8080.

Once the service is started, it can directly access the exposed endpoint. Because the first method exposed is a GET call, you can use a variety of methods to invoke this service. My preferred approach is to invoke the service using a Chrome-based tool such as POSTMAN or CURL. Figure 1 shows – 5 at http://localhost:8080/v1/organizations/ E254f8c ebe c442-4 – a82a e2fc1d1ff78a/licenses/f3831f8c – ebe c338-4 – a82a – e2fc1d1ff78a endpoint on a GET request.

We now have a running skeleton of a service. But from a development perspective, the service is incomplete. Good microservice design inevitably divides services into well-defined layers of business logic and data access.

Let’s take a final look — exploring how DevOps engineers implement services and package them for deployment to the cloud.




For DevOps engineers, the design of microservices is about managing the service once it goes into production. Writing code is often simple, but keeping it running is difficult.

Although DevOps is a rich and emerging FIELD of IT, later in this book, readers will start microservices development based on four principles and build around them. These principles are detailed below.

(1) Microservices should be independent and independently deployable, and multiple service instances can be started and disassembled using a single software artifact.

(2) Microservices should be configurable. When a service instance starts, it should either read the data it needs to configure itself from a central location or have its configuration information passed as an environment variable. Configuring services requires no human intervention.

(3) The microservice instance needs to be transparent to the client. The client should not know the exact location of the service. Instead, the microservice client should communicate with a service discovery broker, which will allow applications to locate instances of microservices without knowing their physical location.

(4) Microservices should communicate their health message, which is a key part of cloud architecture. Once the microservice instance fails, the client needs to bypass the bad service instance.

These four principles reveal the paradox of microservice development. Microservices are smaller in scale and scope, but using microservices introduces more moving parts into the application, especially since microservices are distributed and run independently of each other in its own distributed container, introducing a high degree of coordination and a higher risk of failure points for the application.

From a DevOps perspective, the operational requirements of microservices must be addressed and these four principles translated into a series of lifecycle events that occur every time a microservice is built and deployed into the environment. These four principles can be mapped to the following operations life cycle steps.

  • Service assembly – How can services be packaged and deployed to ensure repeatability and consistency so that the same service code and runtime are deployed exactly the same?

  • Service boot — How do you separate application – and environment-specific configuration code from runtime code so that microservice instances can be quickly started and deployed in any environment without human intervention to configure microservices?

  • Service registration/Discovery – When deploying a new microservice instance, how to make the new service instance discoverable by other application clients.

  • Service Monitoring – In a microservice environment, it is common to run multiple instances of the same service due to high availability requirements. From a DevOps perspective, you need to monitor the microservice instances and ensure that any failures in the microservices are bypassed and that the service instances that are in poor condition are disassembled.

Figure 1-6 shows how these four steps fit together.



1.4.1 Service Assembly: Package and deploy microservices

From a DevOps perspective, one of the key concepts behind microservices architecture is the ability to rapidly deploy multiple instances of microservices in response to changing application environments (such as sudden influx of user requests, problems within the infrastructure, and so on).

To achieve this, microservices need to be packaged and installed as a single artifact with all dependencies, which can then be deployed to any server with a Java JDK installed. These dependencies also include runtime engines (such as HTTP servers or application containers) that host microservices.

This process of continuous build, package, and deployment is service assembly (step 1 in Figure 1-6). Figure 1-7 shows additional details about the service assembly steps.

Fortunately, almost all Java microservices frameworks include runtime engines that can be packaged and deployed using code. For example, in the Spring Boot example in Figure 2-7, you can use Maven and Spring Boot to build an executable Java JAR file that has an embedded Tomcat engine built into it. The following command line example builds the license service as an executable JAR and then starts the JAR file from the command line:

For some operations teams, the idea of embedding a runtime environment in a JAR file is a major shift in how they deploy applications. In a traditional J2EE enterprise organization, applications are deployed to application servers. This model means that the application server is itself an entity and is typically managed by a team of system administrators who manage the configuration of the server regardless of the application being deployed.

The separation of the application server configuration from the application can introduce points of failure during deployment, as in many organizations the configuration of the application server is not controlled by source and is managed through a user interface and a combination of local administrative scripts. This is very easy to configure drift in an application server environment and suddenly cause what appears to be a random interruption.

Embedding the runtime engine in deployable artifacts eliminates many possibilities for configuration drift. It also allows entire artifacts to be under source control and allows application teams to think better about how their applications are built and deployed.

1.4.2 Service Boot: Manage the configuration of microservices

Service boot (Step 2 in Figure 1-6) occurs when the microservice is first started and needs to load its application configuration information. Figure 1-8 provides more context for boot processing.

As any application developer knows, there are times when you need to make your application’s runtime behavior configurable. Typically this involves reading the application’s configuration data from the application’s deployed properties file or from a data store, such as a relational database.

Microservices typically encounter the same type of configuration requirements. The difference is that hundreds or even thousands of microservice instances may be running in a microservice application running on the cloud. To complicate matters further, these services may be scattered around the globe. Because of the large number of geographically dispersed services, redeploying services to capture new configuration data becomes difficult.

Storing data in a data store outside the server solves this problem, but microservices on the cloud present a unique set of challenges.

(1) The structure of configuration data is often simple, usually read frequently but not often written. In this case, using a relational database is a dead end, because it is designed to manage a data model that is more complex than a simple set of key-value pairs.

(2) Because the data is accessed regularly but rarely changed, it must be readable with low latency.

(3) The data store must be highly available and close to the service that reads the data. The configuration data store cannot be completely shut down, or it will become a single point of failure for the application.

1.4.3 Service Registration and Discovery: How does the client communicate with microservices

From a microservices consumer’s perspective, microservices should be location-transparent, since servers are ephemeral in a cloud-based environment. Ephemeral means that servers hosting services typically have shorter lifespans than services running in enterprise data centers. Cloud-based services can be quickly started and dismantled with a brand new IP address assigned to the server running the service.

By insisting on treating services as ephemeral, disposable objects, microservice architectures can achieve a high degree of scalability and availability by running multiple service instances. Service requirements and resilience can be managed as quickly as needed. Each service has a unique and non-permanent IP address assigned to it. The downside of ephemeral services is that managing a large number of ephemeral services manually or manually can cause outages as services come and go.

Microservice instances need to be registered with third-party agents. This registration process is called service discovery (see Step 3 in Figure 1-6 and details about this process in Figure 1-9). When a microservice instance registers with a service discovery agent, the microservice instance tells the discovery agent two things: the physical IP address or domain name address of the service instance, and the logical name that the application can use to look up the service. Some service discovery agents also require access to the URL of the registered service, which the service discovery agent can use to perform health checks.

The service client then communicates with the discovery agent to find the location of the service.

2.4.4 Communicate the “health status” of micro-services

The service discovery agent does more than act as a traffic cop guiding clients to service locations. In a cloud-based microservice application, it is common to have multiple service instances running, some of which sooner or later will have some problems. The service discovery broker monitors the health of each service instance it registers and removes problematic service instances from its routing table to ensure that clients do not access failed service instances.

After a microservice is discovered, the service discovery agent continues to monitor and ping the health check interface to ensure that the service is available. This is step 4 in Figure 1-6. Figure 1-10 provides a context for this step.

By building a consistent health check interface, we can use cloud-based monitoring tools to detect problems and respond appropriately to them.

If the service discovery agent discovers a problem with a service instance, it can take corrective action, such as shutting down the failed instance or starting another service instance.

In a microservice environment using REST, the easiest way to build a health check interface is to expose HTTP endpoints that return JSON net loads and HTTP status codes. In non-Spring Boot-based microservices, developers often need to write an endpoint that returns the health of the service.

In Spring Boot, exposing an endpoint is simple and involves modifying the Maven build file to include the Spring Actuator module. Spring Actuator provides out-of-the-box operation and maintenance endpoints that help users understand and manage the health of services. To use Spring Actuator, make sure you include the following dependencies in your Maven build file:

If visit http://localhost:8080/health terminals on the license service, should see the return of health data. Figure 1-11 provides an example of the returned data.

As shown in Figure 1-11, health checking is more than just an indicator of whether a microservice is running. It can also provide information about the status of the server running the microservice instance, which can provide a richer monitoring experience.




Microservices in the cloud may seem simple, but success requires an integrated perspective, blending the perspectives of architects, developers, and DevOps engineers into one tightly integrated perspective. The key conclusions from each perspective are summarized below.

(1) Architect — focus on the natural contours of business problems. Identify target candidate microservices by describing the business problem domain and hearing stories from others. Also keep in mind that it is better to start with “coarse-grained” microservices and refactor to smaller services than to start with a large number of small services. Microservices architectures, like most good architectures, are tailored on demand, not pre-planned.

(2) Software engineers — Just because the service is small doesn’t mean you should throw good design principles out the window. Focus on building layered services where each layer has discrete responsibilities. Avoid the temptation to build frameworks in code and try to make each microservice completely independent. Premature framework design and adoption can incur significant maintenance costs later in the application life cycle.

(3) DevOps engineers — Services don’t exist in a vacuum. Establish the service lifecycle early. The DevOps perspective focuses not only on automating the construction and deployment of services, but also on monitoring the health of services and responding to problems when they occur. Implementing services often requires more work and forethought than writing business logic.

1.6 summary

  • Success with microservices requires a combination of architect, software developer, and DevOps perspectives.

  • Microservices are a powerful architectural paradigm that has both advantages and disadvantages. Not all applications should be microservice applications.

  • From an architect’s perspective, microservices are small, independent, and distributed. Microservices should have narrow boundaries and manage a small set of data.

  • From a developer’s point of view, microservices are typically built using a REST-style design, with JSON as a net load for the service to send and receive data.

  • Spring Boot is an ideal framework for building microservices because it allows developers to build REST-based JSON services with a few simple annotations.

  • From a DevOps perspective, how microservices are packaged, deployed, and monitored is critical.

  • Out of the box. Spring Boot allows users to deliver services with a single executable JAR file. The embedded Tomcat server in the JAR file hosts the service.

  • Spring Actuator that comes with the Spring Boot framework exposes information about the health of the service as well as information about when the service is running.



“Spring Micro Service Combat”

By John Carnell

Click on the link to buy the paper book


This book introduces Spring system (Spring ->Spring Boot->Spring Cloud) under microservices architecture in detail, helping Java developers to quickly split individual applications, and encapsulating the whole life process of microservices, greatly simplifying the development process.

This book teaches you how to design microservices while building and deploying Spring cloud applications. The whole book is a complete example of the author’s years of valuable experience.

The book focuses on a project named EagleEye, introduces concepts like Cloud and microservices, as well as many Spring projects like Spring Boot and Spring Cloud. It also introduces how to rebuild EagleEye project from individual architecture to microservice architecture step by step. Finally, the project will be divided into many micro-services, which will run in their own Docker containers to achieve continuous integration/continuous deployment, and eventually automatically deploy to the cloud environment (Amazon). This book presents a core pattern for solving the typical problems of microservice development (including development, testing, and operations) encountered during the refactoring process, and then selects specific Spring Cloud subprojects or other tools to solve these problems in the field.


This article is excerpted from the asynchronous community. This article uses Spring Boot to build microservices.

  • Small welfare

  • Pay attention to [asynchronous community] service number, forward this article to the circle of friends or more than 50 people wechat group, send screenshots to the background of asynchronous community service number, and leave a message at the bottom of the article you learn micro service/architecture or try to read the book feelings, we will select 3 readers to present “Spring micro service practice” 1, quickly and actively participate in it! Deadline: June 14, 2018

Scan for us

If you reply “follow” in the background of “Asynchronous Community”, you can get 2000 online video courses for free


Read the original article, buy “Spring Micro Service Field”