Spring Cloud Getting Started Tutorial - Hystrix Circuit Breaker for Fault Tolerance and Degradation

Introduction

Spring cloud provides the Hystrix fault tolerance library to implement a downgrade strategy for methods configured with circuit breakers and temporarily invoke alternate methods when services are unavailable. This article will create a product microservice, register it with the eureka service registry, then we use the web client to access the /productsAPI to get the product list, and when the product service fails, call the local backup method to degrade but provide services normally.

basic environment

  • JDK 1.8
  • Maven 3.3.9
  • IntelliJ 2018.1
  • Git

Project source code

Gitee Code Cloud

Add products and services

Create a new maven project in intelliJ with the following configuration

  • groupId: cn.zxuqian
  • artifactId: productService

Then add the following code to pom.xml:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>cn.zxuqian</groupId>
    <artifactId>productService</artifactId>
    <version>1.0-SNAPSHOT</version>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.0.1.RELEASE</version>
        <relativePath/>
    </parent>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <java.version>1.8</java.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-config</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>
    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-dependencies</artifactId>
                <version>Finchley.M9</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

    <repositories>
        <repository>
            <id>spring-milestones</id>
            <name>Spring Milestones</name>
            <url>https://repo.spring.io/libs-milestone</url>
            <snapshots>
                <enabled>false</enabled>
            </snapshots>
        </repository>
    </repositories>

</project>

We went ahead and used it spring-cloud-starter-netflix-eureka-clientto automatically register the product service with the eureka service. Then also used to spring-cloud-starter-configread the configuration file of the configuration service center. This project is just a simple spring web project.

src/main/resourcesCreate a bootstrap.ymlfile under and add the following:

spring:
  application:
    name: product-service
  cloud:
    config:
      uri: http://localhost:8888

Create a file in the git repository of the configuration center, product-service.ymladd the following configuration and submit:

server:
  port: 8081

This configuration specifies port 8081 for product services. Then create a Applicationclass and add the following code:

package cn.zxuqian;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;

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

@EnableDiscoveryClientThe annotation will instruct spring cloud to automatically register this service with eureka. Finally, create a cn.zxuqian.controllers.ProductControllercontroller, provide an /productsAPI, and return sample data:

package cn.zxuqian.controllers;

import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class ProductController {

    @RequestMapping("/products")
    public String productList() {
        return "外套,夹克,毛衣,T恤";
    }
}

Configure the web client

Open the webproject we created earlier pom.xmland add a new Hystrixdependency in:

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
</dependency>

Then update Applicationthe code of the class:

package cn.zxuqian;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.web.client.RestTemplateBuilder;
import org.springframework.cloud.client.circuitbreaker.EnableCircuitBreaker;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.context.annotation.Bean;
import org.springframework.web.client.RestTemplate;

@EnableCircuitBreaker
@EnableDiscoveryClient
@SpringBootApplication
public class Application {

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

    @Bean
    public RestTemplate rest(RestTemplateBuilder builder) {
        return builder.build();
    }
}

This is used @EnableCircuitBreakerto turn on the circuit breaker function, and then also add a restmethod and use the @Beanannotation. This part belongs to Spring's dependency injection feature, using @Beanthe marked method will tell how to initialize such an object, for example, in this case it is used RestTemplateBuilderto create an RestTemplateobject, which will be used later in the service using the circuit breaker.

Create a cn.zxuqian.service.ProductServiceclass and add the following code:

package cn.zxuqian.services;

import com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.client.discovery.DiscoveryClient;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;

import java.util.List;

@Service
public class ProductService {

    private final RestTemplate restTemplate;

    @Autowired
    private DiscoveryClient discoveryClient;

    public ProductService(RestTemplate restTemplate) {
        this.restTemplate = restTemplate;
    }

    @HystrixCommand(fallbackMethod = "backupProductList")
    public String productList() {
        List<ServiceInstance> instances = this.discoveryClient.getInstances("product-service");
        if(instances != null && instances.size() > 0) {
            return this.restTemplate.getForObject(instances.get(0).getUri() + "/products", String.class);
        }

        return "";
    }

    public String backupProductList() {
        return "夹克,毛衣";
    }
}

The reason for creating a Service class is because Hystrix can only be used in classes marked with @Serviceor @Component, so that the API provided by Spring Context can be used normally. This will be explained later when we go deeper into Spring. After using the @HystrixCommandannotation, Hystrix will monitor the annotated method productList(the bottom layer uses a proxy to wrap this method to achieve monitoring). Once the errors of this method accumulate to a certain threshold, the circuit breaker will be activated, and all subsequent productListrequests to call the method will be fails, the fallbackMethodspecified method is called temporarily backupProductList(), and then when the service returns to normal, the circuit breaker is closed. We also use DiscoveryClientthe uri address to find the product service in this class, use spring.application.namethe value of the configuration item of the product service, that is, product-serviceas the method serviceIDpassed to discoveryClient.getInstances(), and then return a list, because currently we only have one product service started, so only You need to take the uri address of the first instance. Then we use RestTemplatethe api to access the product service. Note that Spring's constructor injection is used here, that is, @Beanthe method we used to annotate before will be used to initialize the restTemplatevariable, and we don't need to initialize it manually. RestTemplateThe class provides getForObject()methods to access other Rest APIs and wrap the results in the form of objects. The first parameter is the uri address of the api to be accessed, and the second parameter is the type of the result obtained. Here we return a String, so pass to him String.class. backupProductList()The method returns the downgraded product list information.

Finally create a controller cn.zxuqian.controllers.ProductControllerand add the following code:

package cn.zxuqian.controllers;

import cn.zxuqian.services.ProductService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class ProductController {

    @Autowired
    private ProductService productService;

    @RequestMapping("/products")
    public String productList() {
        return productService.productList();
    }
}

Here is used to provide data ProductServicefor the /productspath.

test

First, we use the spring-boot:runplug-in to start the configuration center service, config-server, then start eureka-server, then product-service, and finally start the web client, wait for a while and wait for the eureka service to be successfully registered to access http://localhost:8080/products, under normal circumstances, the 外套,夹克,毛衣,T恤result will be obtained , then we close product-service, and then access the same path, we will get the downgraded result:夹克,毛衣

Welcome to my blog http://zxuqian.cn/spring-cloud-tutorial-hystrix/

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=325271153&siteId=291194637