How to Create Microservices with Spring Cloud and Spring Cloud Netflix

H

Microservice architecture has gained great popularity in recent times. It achieves simplicity in our services and thus ensures a less complex maintenance. Today, Will Manuel Leyton, shows us the implementation of microservices with Spring Cloud and Spring Cloud Netflix.

Netflix OSS and Spring Cloud managed to abstract diverse patterns (Api Gateway, Service Registry, Externalized Configuration, Circuit Breaker, Distributed Tracing, etc) that allow us to focus only on developing specific components of our business domain, saving us time with this.

Today we will implement microservices with Spring Cloud and Spring Cloud Netflix stacks, which encapsulates the most popular components of Netflix OSS and integrates with Spring Boot applications.

Pre – Requirements

  1. Java >= 8.
  2. Git.
  3. Gradle.
  4. Knowledge in Spring Boot.
  5. GitHub Account
  6. IDE for Java (Eclipse, IntellIJ, etc).
  7. Lombok
  8. Internet

Learning flow

1. Develop Service Registry with Eureka
2. Develop Configuration Server with Spring Cloud Config
3. Develop API Gateway with Zuul
4. Develop Microservices   Microservice greeting-service Microservice meddle-service
5. Implement Circuit Breaker for Faults with Hystrix
6. Implement Traceability with Sleuth

1. Development of Service Registry with Eureka

The service registry pattern allows the different services and instances to be registered in a server that acts as a database, which is consulted through an API and discover instances based on an identifier, Eureka is a registry server designed by Netflix OSS.

In order to develop the Eureka server we must follow the following steps:

  1. Go to spring initializr: https://start.spring.io
  2. Create register-server project with the following specifications: Select the dependencies: Eureka Server, Actuator and DevTools and then click on the Generate Project button, which will download a project.
  3. Import Project gradle in our IDE.
  4. Note RegisterServerApplication launcher class with @EnableEurekaServer to enable a registry server:
  1. @EnableEurekaServer
  2. @SpringBootApplication
  3. public class RegisterServerApplication {
  4.  
  5.       public static void main(String[] args) {
  6.       SpringApplication.run(RegisterServerApplication.class, args);
  7.       }
  8. }
  1. Rename archivo application.properties por bootstrap.yml y agregar:
  2. application.properties to bootstrap.yml and add:
  3. server:
  4.   port: ${EUREKA_PORT:8761}
  5.  
  6. spring:
  7.   application:
  8.       name: register-server
  9.  
  10. eureka:
  11.   client:
  12.     register-with-eureka: false
  13.       fetch-registry: false

Where the port, application name and non-registration on the log server are configured.

2. Develop Configuration Server with Spring Cloud Config

The externalized configuration pattern allows you to externalize all the configuration of the applications, such as credentials, etc.

Spring Cloud Config Server is a server that allows to externalize the configuration based on property files in git repositories, database, etc.

To develop the configuration server we must follow the following steps:

  1. Create config-repo repository in GitHub, GitLab, etc.
  2. Add application.yml file in config-repo, which will serve as global configuration for all the microservices connected to the configuration server and add the following configuration:
  1. eureka:
  2. client:
  3. service-url:
  4. defaultZone: ${EUREKA_URI:http://localhost:${EUREKA_PORT:8761}/eureka}
  5. register-with-eureka: true
  1. commit and push to push changes to the remote GitHub repository.
  2. Go to spring initializr: https://start.spring.io
  3. Create config-server  project with the following specifications:
  1. Where we will select the dependencies: Config Server, Eureka Discovery Client, Actuator and DevTools and then click on the Generate Project button, which will download a project.
  2. Import Project gradle into our IDE.
  3. Note launcher class ConfigServerApplication with @EnableDiscoveryClient to enable the client functionality of the Eureka registry server:
    1. @EnableConfigServer
    2. @EnableDiscoveryClient
    3. @SpringBootApplication
    4. public class ConfigServerApplication {
    5.  
    6. public static void main(String[] args) {
    7. SpringApplication.run(ConfigServerApplication.class, args);
    8. }
    9. }
  4. Rename application.properties file by bootstrap.yml and add:
    1. server:
    2.   port: ${CONFIG_PORT:8888}
    3.  
    4. spring:
    5.   application:
    6.       name: config-server
    7.   cloud:
    8.       config:
    9.       server:
    10.       git:
    11.             uri: ${CONFIG_REPO_URI}
    12.             username: ${CONFIG_REPO_USERNAME}
    13.             password: ${CONFIG_REPO_PASSWORD}
    14.  
    15. eureka:
    16.   client:
    17.       service-url:
    18.       defaultZone: ${EUREKA_URI:http://localhost:${EUREKA_PORT:8761}/eureka}
    19.       register-with-eureka: true

Here you configure the port, application name, log server, configuration server based on its application name and repository credentials, which will provide the configuration files.

The environment variable ${CONFIG_REPO_URI} is the url http of the config-repo repository created in GitHub, ${CONFIG_REPO_USERNAME} and ${CONFIG_REPO_PASSWORD} are the credentials to access the repository.

Find development projects and get hired at zero commission fees 

Browse the latest job openings

3. Develop API Gateway with Zuul

The api gateway pattern allows to create a gateway from external systems to our API’s clouster, based on routing by microservice identifier (application name property). Zuul is a gateway server designed by Netflix OSS.

In order to develop the Api Gateway we must follow the following steps:

  1. Go to spring initializr
  2. Create api-gateway project with the following specifications: Where we will select the dependencies: Zuul, Eureka Discovery Client, Config Client, Actuator and DevTools and then click on the Generate Project button, which will download a project.
  3. Import Project gradle into our IDE.
  4. Note ApiGatewayApplication launcher class with @EnableZuulProxy  to enable gateway functionality and @EnableDiscoveryClient to enable Eureka registry server client functionality:
    1. @EnableZuulProxy
    2. @EnableDiscoveryClient
    3. @SpringBootApplication
    4. public class ApiGatewayApplication {
    5.      
    6.       public static void main (String[] args) {
    7.       SpringApplication.run(ApiGatewayApplication.class, args);
    8.       }
    9. }
  5. Rename application.properties to bootstrap.yml and add:
    1. server:
    2.   port: ${GATEWAY_PORT:9090}
    3.  
    4. spring:
    5.   application:
    6.       name: api-gateway
    7.   cloud:
    8.       config:
    9.       discovery:
    10.       enabled: true
    11.       service-id: config-serverWhere you configure the port application name, configuration server based on its application name. This will provide the configuration files.
  6. Create api-gateway.yml file in config-repo and add it to the file:
    1. zuul:
    2.   prefix: /apiWhere the prefix with which requests from external systems will be resolved is configured.
  7. commit and push to push changes to the remote GitHub repository.

4. Develop Microservices

4.1. Microservice greeting-service

We will develop a microservice that exposes a controller that returns a greeting, which will be registered in the register-server and will look for its configuration in config-server.

In order to develop the microservice we must follow the following steps:

  1. Add greeting-service.yml file in config-repo, which will serve as configuration in the default profile for the greeting-service microservice and add the following configuration:
    1. greeting:
    2.   message: Hello
  2. Commit and push to push changes to the remote GitHub repository.
  3. Go to spring initializr
  4. Create greeting-service project with the following specifications:
  5. Here we will select the dependencies: Eureka Discovery Client, Config Client, Web, Lombok, Actuator and DevTools and then click on the Generate Project button, which will download a project.
  6. Import Project gradle into our IDE.
  7. Note GreetingServiceApplication launcher class with @EnableDiscoveryClient to enable the client functionality of the Eureka registry server:
    1. @EnableDiscoveryClient
    2. @SpringBootApplication
    3. public class GreetingServiceApplication {
    4.  
    5. public static void main(String[] args) {
    6.        SpringApplication.run(GreetingServiceApplication.class, args);
    7. }
    8. }
  8. Rename application.properties file by bootstrap.yml and add:
    1. server:
    2.   port: ${GREETING_PORT:8080}
    3.  
    4. spring:
    5.   application:
    6. name: greeting-service
    7.   cloud:
    8. config:
    9.        discovery:
    10.        enabled: true
    11.        service-id: config-server
  9. Create package dto and add class GreetingResponse:
    1. @Getter
    2. @Setter
    3. @NoArgsConstructor
    4. @AllArgsConstructor
    5. public class GreetingResponse {
    6.  
    7.     private String message;
    8. }
  10. Create service.inter package and add GreetingService interface:
    1. public interface GreetingService {
    2.  
    3.     GreetingResponse greeting(String name);
    4. }
  11. Create service.impl package and add GreetingServiceImp implementation:
    1. @Service
    2. public class GreetingServiceImp implements GreetingService {
    3.  
    4.     @Value(
    5.              value = “${greeting.message}”)
    6. String baseMessage;
    7.  
    8. @Override
    9. public GreetingResponse greeting(String name) {
    10.        String message = baseMessage + ” ” + name;
    11.        return new GreetingResponse(message);
    12. }
    13. }
  12. Create controller package and add GreetingController interface:
    1. @RestController
    2. @AllArgsConstructor
    3. @RequestMapping(
    4.        value = {
    5.              “/greeting”
    6.        })
    7. public class GreetingController {
    8.  
    9. private GreetingService greetingService;
    10.  
    11. @GetMapping
    12. public ResponseEntity<GreetingResponse> greeting(@RequestParam(
    13.              value = “name”) String name) {
    14.        return ResponseEntity.ok(greetingService.greeting(name));
    15. }
    16. }

4.2. Microservice middle-service

We will develop a microservice that exposes a controller that allows us to communicate with greeting-service. The microservice will be registered in the register-server and will look for its configuration in config-server. In order to develop the microservice we must follow the following steps:

  1. Add meddle-service.yml file in config-repo, which will serve as configuration in the default profile for the meddle-service microservice.
  2. commit and push to push changes to the remote GitHub repository.
  3. Go to spring initializr
  4. Create meddle-service project with the following specifications:
  5. Where we will select the dependencies: Eureka Discovery Client, Config Client, Web, Lombok, Ribbon, Actuator and DevTools and then click on the Generate Project button, which will download a project.
  6. Import Project Gradle into our IDE.
  7. Note MeddleServiceApplication launcher class with @EnableDiscoveryClient to enable the client functionality of the Eureka registry server:
    1. @EnableHystrix
    2. @EnableDiscoveryClient
    3. @SpringBootApplication
    4. public class MeddleServiceApplication {
    5.  
    6.       public static void main(String[] args) {
    7.       SpringApplication.run(MeddleServiceApplication.class, args);
    8.       }
    9. }
  8. Rename application.properties file by bootstrap.yml and add:
    1. server:
    2.   port: ${MEDDLE_PORT:8090}
    3.  
    4. spring:
    5.   application:
    6.       name: meddle-service
    7.   cloud:
    8.       config:
    9.       discovery:
    10.       enabled: true
    11.       service-id: config-server
  9. Create package configuration and add AppConfiguration class, where we will configure the bean RestTemplate annotated with @LoadBalanced to allow the balance by ribbon and the list of instances supplied by the register-server:
    1. @Configuration
    2. public class AppConfiguration {
    3.  
    4.     @Bean
    5.       @LoadBalanced
    6.       public RestTemplate restTemplate(RestTemplateBuilder builder) {
    7.       return builder.build();
    8.       }
    9. }
  10. Create package dto and add class GreetingResponse:
    1. @Getter
    2. @Setter
    3. @NoArgsConstructor
    4. @AllArgsConstructor
    5. public class GreetingResponse {
    6.  
    7.     private String message;
    8. }
  11. Create service.inter package and add GreetingClient interface:
    1. public interface GreetingClient {
    2.  
    3.     GreetingResponse greeting(String name);
    4. }
  12. Create service.impl package and add GreetingClientImp implementation:
    1. @Service
    2. @AllArgsConstructor
    3. public class GreetingClientImp implements GreetingClient {
    4.  
    5.       private static final String NAME_PARAM_KEY = “name”;
    6.  
    7.       private static final String GREETING_SERVICE_URL = “http://greeting-service/greeting?name={name}”;
    8.  
    9.       private RestTemplate restTemplate;
    10.  
    11.       @Override
    12.       public GreetingResponse greeting(String name) {
    13.       Map<String, Object> parameters = new HashMap<>();
    14.       parameters.put(NAME_PARAM_KEY, name);
    15.       return restTemplate.getForObject(GREETING_SERVICE_URL, GreetingResponse.class, parameters);
    16.       }
    17. }
  13. Create controller package and add MeddleController interface:
    1. @RestController
    2. @AllArgsConstructor
    3. @RequestMapping(
    4.       value = {
    5.             “/meddle”
    6.       })
    7. public class MeddleController {
    8.  
    9.       private GreetingClient greetingClient;
    10.  
    11.       @GetMapping(
    12.             value = {
    13.                   “/greeting”
    14.             })
    15.       public ResponseEntity<GreetingResponse> greeting(@RequestParam(
    16.             value = “name”) String name) {
    17.       return ResponseEntity.ok(greetingClient.greeting(name));
    18.       }
    19. }

5. Implement Circuit Breaker for Failures with Hystrix

When we communicate with different systems it is possible that failures may occur and these propagate, affecting our system and generating a potential consumption of resources, so the circuit breaker pattern helps us with this type of problem.

Circuit breaker works by opening a short circuit when a threshold of consecutive failures is reached. This short circuit makes a call to a fallback function, achieving that we do not spend resources in the following attempts of call until the circuit passes to the state of half open. Then new attempts towards the external system will be made, in which if a failure is presented the short circuit is opened again.

We will make the implementation of this pattern with the Hystrix library of Netflix OSS in the middle-service: microservice:

  1. Add Hystrix dependency in our build.gradle file of the meddle-service microservice:
    implementation ‘org.springframework.cloud:spring-cloud-starter-netflix-hystrix’.
  2. Update GreetingClientImp class by adding HystrixCommand and fallback method:
    1. @Service
    2. @AllArgsConstructor
    3. public class GreetingClientImp implements GreetingClient {
    4.  
    5.       private static final String NAME_PARAM_KEY = “name”;
    6.  
    7.       private static final String GREETING_SERVICE_URL = “http://greeting-service/greeting?name={name}”;
    8.  
    9.       private RestTemplate restTemplate;
    10.  
    11.       @Override
    12.       @HystrixCommand(
    13.             fallbackMethod = “greetingFallback”)
    14.       public GreetingResponse greeting(String name) {
    15.       Map<String, Object> parameters = new HashMap<>();
    16.       parameters.put(NAME_PARAM_KEY, name);
    17.       return restTemplate.getForObject(GREETING_SERVICE_URL, GreetingResponse.class, parameters);
    18.       }
    19.  
    20.       public GreetingResponse greetingFallback(String name) {
    21.       return new GreetingResponse(name + “, an error occurred”);
    22.       }
    23. }

6. Implement Traceability with Sleuth

The distributed tracing pattern allows us to track the flows of requests between our different components of the mounted architecture, adding ID’s to identify the request that can be identified in the log’s.

  1. Add Sleuth dependency in our build.gradle files of api-gateway, greeting-service and middle-service :

implementation ‘org.springframework.cloud:spring-cloud-starter-sleuth’

7. Running Applications

  1. Run register-server.
  2. Run config-server.
  3. Run api-gateway.
  4. Run greeting-service.
  5. Run meddle-service.
  6. Test:

curl -X GET ‘http://localhost:9090/api/meddle-service/meddle/greeting?name=YourName’ -H ‘cache-control: no-cache’

Conclusion

The components provided by Spring Cloud and Spring Cloud Netflix facilitate the implementation of the most popular patterns for the development of microservices, saving coding time and guaranteeing stability, as their components are highly welcomed by the developer community.

Will Manuel Leyton
By Will Manuel Leyton

Recent Posts