Skip to main content

Microservices with Spring Boot

What are Microservices?

Introduction

The term "microservices" appears in many technology journals these days. This blog addresses common questions including: "What are microservices, and more importantly, how are they a better solution than what's already out there? Also, if microservices are so great, how easy is it to develop microservices?" Microservices are stand-alone applications that break down functionality into fine-grained components that run and restart independently.

The Problem

The problem with large, monolithic applications is that they are difficult to maintain, test, and extend. Component architectures such as COM, SOA, etc. promised reusability but led to proliferations of libraries that became hard to maintain as well (e.g., DLL hell or JAR hell, etc.). Microservices with Spring Cloud promise faster change, greater availability, fine-grain scaling, and better adaptation to DevOps thinking. They typically use REST and HTTP to decouple components, leading to easier scalability. With Spring Cloud and Spring Boot, you get an opinionated framework that reduces the work required when developing services while offering flexibility when you need to customize your system.

The Solution

Core Characteristics of Microservices Include:

  • Components exposed as services: Services are registered in a registry.
  • Tied to a specific domain: Services can focus on their own work rather than being tied to the workings of other services.
  • Loosely coupled: There's a natural separation of concerns, since the services can focus on their individual work. This narrowed focus reduces concerns such as how the services talk to each other or what's going on inside the other services.
  • Built to tolerate failure: Because components are not intertwined, the system is built to allow services to be automatically retried when a down service returns to health. Systems are assumed to fail, so resiliency is baked right in.
  • Delivered continuously via automation: Services can be updated independently and deployed without disturbing other components.
  • Built and ran by independent teams: Teams can "divide and conquer" by splitting the work into smaller components that don't disturb each other.

Components of Spring Cloud Thanks to Netflix®:

  • Service registry and discovery in Spring Cloud Eureka
  • Circuit breaking technology in Spring Cloud Hystrix
  • Client-side load balancing in Spring Cloud Ribbon
  • Service proxying and API gateway via Spring Cloud Zuul
  • Messaging (Kafka, Rabbit MQ, etc.) through Spring Cloud Stream
  • Data processing pipelines with Spring Cloud Data Flow
  • Convenient name proxies with Feign

Real World Use Cases for Microservices

Our recent work with a client allowed us to have a hands-on experience with microservices in a real-world education environment. We were able to deploy developers across multiple parts of the system and have them work independently to bring the system forward. In addition, we took advantage of a mixed online and local environment, to isolate components used only for development from deployed components. Eventually, we did end up with a local deployment for improved performance (initially getting things working online). Also, we used Vagrant to deploy a complete development environment for the developers working on the front end. This lessened concerns regarding wiring up microservices or having to stub out services, enabling front end developers to come up to speed quickly.

Microservices In Action: A Vending Machine Service

Application Background

Now, let's look at microservices in action for a real-world application. In this case, we are starting with a service to display the inventory in a vending machine. We will illustrate a problem with the application and see how Spring Cloud's Eureka can better separate the client from the server. A client (e.g., a mobile app or mobile-responsive web app) could talk directly to the vending machine. While this can be demonstrated using an HTTP lookup, the following example will simply use localhost.

This code was created using Spring Tool Suite (STS) based on Eclipse and Maven; however, the code was initiated using Spring Initializr at http://start.spring.io .

Application in Action

For our model, we have a vending machine (i.e., a dispenser) containing sleeves of items. Each item is either a can or bottle with a brand associated with it. In our example, the inventory is hard-coded, but live.

Produce an inventory in JSON of the products in the dispenser:
http://localhost:8086/inventory

Microservices with Spring Boot

Withdraw a beverage item and update the inventory:
http://localhost:8085/beverage/{line}

Microservices with Spring Boot

{line} is a value from 0-4 corresponding to the brand dispensing line in our stock inventory.

To display the current contents in a client, we have a second service that simply calls the above directly to display the current inventory:
http://localhost:8086/dispenser

Microservices with Spring Boot

(This is before withdrawing a beverage as in the above URL)

Repeatedly hitting the beverage line will deplete the inventory:

Microservices with Spring Boot

One of the many benefits of microservices architecture is to decouple the client from service; we can use the Eureka service registry as a means to discover services rather than hard-coding websites or references into code. Now, if the server remains at a fixed address or domain, we would have no difficulty; however, if the client were, say, embedded within a mobile web application, we would need to update the client every time the server name changed. Moreover, we would need to rely on a hardware load balancer to scale up on load. Instead, we can use the Eureka service to make the server discoverable by the client and we then demonstrate how to decouple the services.

Installing the Application

Steps:

        1. Create a development directory for the Vending Machine software
          1. $ cd <working-directory>
          2. For me, this is
            $ cd /Users/fredericvanwest/Downloads/VendingMachine/checkout
            $ mkdir VendingMachine
            $ cd VendingMachine
        2. Clone the repositories from git
          1. From the UNIX command line, clone the repository
            1. $ git clone https://github.com/fredvanwest/vending-machine-service.git
            2. $ git clone https://github.com/fredvanwest/vending-machine-client.git
          2. This will retrieve the sample repositories and stage them for development
        3. Import the vending-machine-service into Spring Tool Suite
          1. Launch Spring Tool Suite

            Microservices with Spring Boot

          2. From Package Explorer, right-click and select "Import…"

            Microservices with Spring Boot

          3. Select "Maven > Existing Maven Projects"

            Microservices with Spring Boot

          4. Select "Next"
          5. In "root directory" navigate to the working directory:

            Microservices with Spring Boot

          6. Click "Open"
          7. At this point, select the /vending-machine-service/pom.xml file:

            Microservices with Spring Boot

          8. Click "Finish"
          9. The project should build immediately
          10. Under the "Boot Dashboard", "Local > vending-machine-service", right-click and select "(Re)start":

            Microservices with Spring Boot

            Microservices with Spring Boot

          11. This will start the service running on port 8086:

            Microservices with Spring Boot

            Microservices with Spring Boot

            This will start the service running on port 8086

          12. If port 8086 is unavailable, you'll need to adjust in the application.properties file under "src > main > resources":

            Microservices with Spring Boot

          13. You can test if the service is running by opening a web browser and hitting the URL
            1. http://localhost:8086/inventory (See above as well)
            2. You should see that the following returned:

              {"sleeves":[{"items":[{"type":"can","brand":"Coke"},{"type":"can","brand":"Coke"},{"type":"can","brand":"Coke"}]},{"items":[{"type":"can","brand":"Diet Coke"},{"type":"can","brand":"Diet Coke"}]},{"items":[{"type":"can","brand":"Sprite"}]},{"items":[{"type":"can","brand":"Dr. Pepper"},{"type":"can","brand":"Dr. Pepper"}]},{"items":[{"type":"bottle","brand":"Dasani"},{"type":"bottle","brand":"Dasani"},{"type":"bottle","brand":"Dasani"},{"type":"bottle","brand":"Dasani"}]}]}​

        4. Import the vending-machine-client into Spring Tool Suite:

          Microservices with Spring Boot

          1. From Package Explorer, right-click and select "Import…"
          2. Select "Maven > Existing Maven Projects":

            Microservices with Spring Boot

          3. Select "Next"
          4. In "root directory" navigate to the working directory:

            Microservices with Spring Boot

            Microservices with Spring Boot

            In "root directory" navigate to the working directory

          5. Click "Open"
          6. At this point, select the /vending-machine-client/pom.xml file:

            Microservices with Spring Boot

          7. Click "Finish"
          8. The project should build immediately
          9. Under the "Boot Dashboard", "Local > vending-machine-client", right-click and select "(Re)start":

            Microservices with Spring Boot

            Microservices with Spring Boot

          10. This will start the client running on port 8085
          11. If port 8085 is unavailable, you'll need to adjust in the application.properties file under "src > main > resources":

            Microservices with Spring Boot>

          12. You can test that the service is running by opening a web browser and hitting the URL:
            1. http://localhost:8085/dispenser (See above illustrations)
            2. You should see:

              COKE: 3 DIET CODE: 2 SPRITE: 1 DR PEPPER: 2 DASANI:4

            3. Note: The inventory is reset every time that the vending-machine-service is cycled, so the results above can be returned by restarting that service
            4. Also, you can test that the inventory goes down by issuing:
              http://localhost:8086/beverage/0
            5. This will return a JSON representation of an item:
              {"type":"can","brand":"Coke"}
            6. A subsequent call to http://localhost:8085/dispenser will now yield: 

              COKE: 2 DIET CODE: 2 SPRITE: 1 DR PEPPER: 2 DASANI:4

            7. This demonstrates that the COKE inventory dropped by one
            8. Make sure to stop the services in STS before proceeding
        5. Create the Eureka Server
          1. From Package Explorer, right-click and select "New > Spring Starter Project":

            Microservices with Spring Boot

          2. From the dialog, change
            1. Name: vending-machine-server
            2. Group: com.vanwest
            3. Artifact: vending-machine-server
            4. Description: Vending Machine Server
            5. Package: com.vanwest
            6. Uncheck default location and select the same root directory as were used for vending-machine-server and vending-machine-client
            7. Make sure to paste "vending-machine-server" on the end of the Location:

              Microservices with Spring Boot

            8. Click "Next"
            9. Select "Cloud Discovery > Eureka Server":

              Microservices with Spring Boot

            10. Select "Ops > Actuator":

              Microservices with Spring Boot

            11. Click "Finish"
          3. Add Eureka server to code
            1. Open "src > main> java > com.vanwest > VendingMachineServerApplication.java"
            2. Above @SpringBootApplication, add @EnableEurekaServer and fix imports

              Microservices with Spring Boot

            3. Open "src > main > resources > application.properties", and enter:

              server.port=8761
              eureka.client.register-with-eureka=false
              eureka.client.fetch-registry=false
              eureka.datacenter=phoenix
              eureka.environment=development

              Microservices with Spring Boot

          4. Under the "Boot Dashboard", "Local > vending-machine-server", right-click and select "(Re)start":

            Microservices with Spring Boot

            Microservices with Spring Boot

            Microservices with Spring Boot

            Right-click and select "(Re)start"

            1. You can see that Eureka is running by hitting the website:
              http://localhost:8761
            2. You should see that the "test" and "phoenix" environments are displayed
            3. Under "Instances currently registered with Eureka" you should see "No instances available":

              Microservices with Spring Boot

        6. Adjust the vending-machine-service to be a Eureka client
          1. From "Package Explorer" right-click on "vending-machine-service" and select "Maven > Add Dependency":

            Microservices with Spring Boot

            Microservices with Spring Boot

          2. In "Enterd groupi, artifactId or sha1 prefix or pattern (*):" enter: "spring-cloud-starter-eureka"
          3. Select "org.springframework.cloud  spring-cloud-starter-eureka":

            Microservices with Spring Boot

          4. Click "OK"
          5. Open "src > main > java > com.vanwest.Vending.Machine.Service > VendingMachineServiceApplication.java"
          6. Above @SpringBootApplication, add @EnableEurekaClient and fix imports:

            Microservices with Spring Boot

          7. Save the file
          8. Open "src > main> resources > application.properties" and enter:

            eureka.client.register-with-eureka=true
            eureka.client.fetch-registry=true
            eureka.instance.hostname=localhost

            Microservices with Spring Boot

          9. ​Save the file
          10. Right-click on "src > main > resources" and select "New > File" and enter: "bootstrap.properties":

            Microservices with Spring Boot

            Microservices with Spring Boot

          11. Enter: spring.application.name=vending-machine-service
          12. Save the file
          13. Under the "Boot Dashboard" "Local > vending-machine-service" right-click and select "(Re)start":

            Microservices with Spring Boot

            Microservices with Spring Boot

            Under the "Boot Dashboard" "Local > vending-machine-service"

            Microservices with Spring Boot

          14. Assuming you left vending-machine-server running, open:
            http://localhost:8761
          15. Under "Instances currently registered with Eureka" you should see "VENDING-MACHINE-SERVICE":

            Microservices with Spring Boot

          16. You can reassure yourself the service is running with the tests above by opening:
            http://localhost:8086/inventory
        7. Adjust the vending-machine-client to be a Eureka client and use a named servicen in place of the hard-coded address
          1. From "Package Explorer" right-click on "vending-machine-client" and select "Maven > Add Dependency":

            Microservices with Spring Boot

            Microservices with Spring Boot

          2. In "Enter groupid, artifactId or sha1 prefix or pattern (*):" enter: "spring-cloud-starter-eureka"
          3. Select "org.springframework.cloud spring-cloud-starter-eureka":

            Microservices with Spring Boot

          4. Click "OK"
          5. Open "src > main > java > com.vanwest.vendingmachineclient > VendingMachineClientApplication.java"
          6. Above @SpringBootApplication, add @EnableEurekaClient and fix imports:

            Microservices with Spring Boot

          7. Open "src > main > java > com.vanwest.vendingmachineclient > VendingController.java":

            Microservices with Spring Boot

          8. Under "VendingController" enter:

            ​@LoadBalanced
            @Bean
            public RestTemplate restTemplate(RestTemplateBuilder builder) {
                     
            return builder.build();
            }

                    @Autowired
                    private RestTemplate restTemplate;

          9. In method GetDispenser, replace:

            RestTemplate rest = new RestTemplate();
            Dispenser dispenser = rest.getForObject("http://localhost:8086/inventory",
            Dispenser.class);

            with:

            //RestTemplate rest = new RestTemplate();
            //Dispenser dispenser = rest.getForObject("http://localhost:8086/inventory", 
            //Dispenser.class);
            Dispenser dispenser = restTemplate.getForObject("http://vending-machine-service/inventory", Dispenser.class);

            Microservices with Spring Boot

          10. Save the file
          11. Open "src > main> resources > application.properties" and enter:

            eureka.client.register-with-eureka=true
            eureka.client.fetch-registry=true
            eureka.instance.hostname=localhost

            Microservices with Spring Boot

          12. Save the file
          13. Right-click on "src > main > resources" select "New > File" and enter: "bootstrap.properties":

            Microservices with Spring Boot

            Microservices with Spring Boot

          14. Enter: spring.application.name=vending-machine-client
          15. Save the file
          16. Under the "Boot Dashboard", "local > vending-machine-client", right-click and select "(Re)start":

            Microservices with Spring Boot

            Microservices with Spring Boot

              1. Now open:
                http://localhost:8761

            1. Under "Instances currently registered with Eureka" you should see "VENDING-MACHINE-CLIENT":

              Microservices with Spring Boot

            2. You can reassure yourself the service is running with the tests above by hitting:
              http://http://localhost:8086/beverage/0

              Microservices with Spring Boot

              and seeing that the inventory is now reduced in:
              http://localhost:8085/dispenser

              Microservices with Spring Boot

          So here we can see how a direct named URL was replaced with registry lookup in Eureka. The Spring Cloud framework makes it much easier to create microservices and manage them. Additional features, such as circuit breaker technology, can allow a microservice to halt on fault or load and resume when conditions improve without human intervention. Microservice technology is instrumental in deploying fault-tolerant systems, which is especially true in the education domain.

Fred van West

Fred van West

Senior Software Developer
Fred joined Unicon in 2017, and holds a Computer Systems Engineering degree from Arizona State University. He has 28 years of experience in a variety of domains including automated testing, automotive instrumentation, telephony, Interactive Voice Response (IVR), and email automation. Prior to joining Unicon, Fred served as Programmer III and team lead for email automation at Choice Hotels International.