Brief introduction
Spring Cloud provides a hystrix fault-tolerant library to temporarily invoke an alternate method when the service is unavailable, and a downgrade strategy is implemented for the method that configures the circuit breaker. This article creates a product microservices, registers to the Eureka Service registry, and then we use the Web Client Access /products
API to obtain a list of products that, when a product service fails, calls the local fallback method to downgrade but to provide the service normally.
Basic Environment
- JDK 1.8
- Maven 3.3.9
- IntelliJ 2018.1
- Git
Project Source
Gitee Code Cloud
Add a product service
Create a new MAVEN project in IntelliJ, using the following configuration
- GroupId:cn.zxuqian
- Artifactid:productservice
Then add the following code in the Pom.xml:
<?xmlVersion= "1.0" encoding= "UTF-8"?><projectxmlns="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 continue to use it spring-cloud-starter-netflix-eureka-client
to automate the registration of product services to the Eureka service. A spring-cloud-starter-config
configuration file that reads the Configuration service center is also used. This project is just a simple spring Web project.
src/main/resources
under Create a bootstrap.yml
file, add the following:
spring: application: name: product-service cloud: config: uri: http://localhost:8888
Create a file in the configuration center git repository to product-service.yml
add the following configuration and commit:
server: port: 8081
This configuration specifies that the port for the product service is 8081. Then create Application
the class, adding 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@SpringBootApplicationpublicclass Application { publicstaticvoidmain(String[] args) { SpringApplication.run(Application.class, args); }}
@EnableDiscoveryClient
The annotations will instruct spring Cloud to automatically register the service with Eureka. Finally, create cn.zxuqian.controllers.ProductController
the controller, provide /products
the API, return the sample data:
package cn.zxuqian.controllers;import org.springframework.web.bind.annotation.RequestMapping;import org.springframework.web.bind.annotation.RestController;@RestControllerpublicclass ProductController { @RequestMapping("/products") publicproductList() { return"外套,夹克,毛衣,T恤"; }}
Configuring the Web Client
Open the project that we created earlier web
, pom.xml
add dependencies in the new Hystrix
:
<dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-hystrix</artifactId></dependency>
Then update Application
the code for 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 classApplication { Public Static void Main(string[] args) {springapplication.Run(Application.class, args); }@Bean PublicResttemplateRest(Resttemplatebuilder builder) {returnBuilder.Build(); }}
This is used here @EnableCircuitBreaker
to turn on the circuit breaker function, and then add a rest
method and use @Bean
annotations. This is part of the spring Dependency injection feature, which uses @Bean
markup to tell you how to initialize such an object, such as the one used to create an object in this case, which is later used in a RestTemplateBuilder
service that uses a RestTemplate
circuit breaker.
Create cn.zxuqian.service.ProductService
the class 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 classProductservice {Private FinalResttemplate resttemplate;@Autowired PrivateDiscoveryclient discoveryclient; Public Productservice(Resttemplate resttemplate) { This.resttemplate= Resttemplate; }@HystrixCommand(Fallbackmethod ="Backupproductlist") PublicStringProductList() {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 ""; } PublicStringbackupproductlist() {return "jacket, Sweater"; }}
The reason to create a service class is because Hystrix can only be marked as@Service
Or@Component
class, so that the API provided by spring context can be used normally. This will be explained later when we delve into spring.
Use@HystrixCommand
After annotations, Hystrix will monitor the annotated methodproductList
(The bottom layer uses proxy wrapper this method to implement monitoring), once the error of this method accumulates to a certain threshold, it will start the circuit breaker, all subsequent callsproductList
Method fails, and the request is temporarily calledfallbackMethod
The specified methodbackupProductList()
, and then the circuit breaker shuts down when the service returns to normal.
We also used theDiscoveryClient
To find the URI address of the product service, use the product service'sspring.application.name
The value of the configuration item, which isproduct-service
AsserviceID
TodiscoveryClient.getInstances()
method, and then returns a list, because currently only one of our product services is started, so we just need to take the URI address of the first instance.
Then we useRestTemplate
To access the API for the product service, note that the spring constructor injection is used@Bean
The annotated method is used to initialize therestTemplate
variables, which do not require us to initialize manually.RestTemplate
class provides agetForObject()
method to access other rest APIs and wrap the result in the form of an object, the first parameter is the URI address of the API to be accessed, the second parameter is the type of the result obtained, and here we return a string, so pass it to himString.class
。
backupProductList()
method returns the product list information after the downgrade.
Finally, create a controller cn.zxuqian.controllers.ProductController
and 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 Productservic E @RequestMapping ( "/products" ) public String productlist () {return productservice. (); }}
This ProductService
is used to /products
provide data for the path.
Test
First, we use spring-boot:run
plug-ins to start the Configuration Center service, Config-server, then start Eureka-server, then start Product-service, and finally start the Web client, wait a moment for Eureka service to register successfully after access http://localhost:8080/products
, the normal situation will get the 外套,夹克,毛衣,T恤
result, then we close the Product-service, and then access the same path, will be degraded after the result:夹克,毛衣
Welcome to visit my blog http://zxuqian.cn/spring-cloud-tutorial-hystrix/
Spring Cloud Getting Started tutorial-hystrix circuit breaker for fault tolerance and demotion