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:
<?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>spri Ng-boot-starter-parent</artifactid> <version>2.0.1.RELEASE</version> <relativePath/> </parent> <properties> <project.build.sourceencoding>utf-8</project.build.sourceencodin g> <java.version>1.8</java.version> </properties> <dependencies> <depend Ency> <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</ar tifactid> </dependency> <dependency> <groupid>org.springframework.boot</g Roupid> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope > </dependency> </dependencies> <dependencyManagement> <dependencies> <dependency> <groupId>org.springframework.cloud</groupId> <artifa Ctid>spring-cloud-depEndencies</artifactid> <version>Finchley.M9</version> <type>pom</ type> <scope>import</scope> </dependency> </dependencies> & lt;/dependencymanagement> <build> <plugins> <plugin> <groupid& Gt;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</ena bled> </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@SpringBootApplicationpublic class Application { public static void main(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;@RestControllerpublic class ProductController { @RequestMapping("/products") public String productList() { 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@springbootapplicationpublic 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 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; @Servicepublic 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 "jacket, sweater"; }}
The
Creates a Service class because hystrix can only be used in classes marked as @Service
or @Component
, so that the spring can be used normally The API provided by the context. This will be explained later when we delve into spring. Br/> using the ' @HystrixCommand ' annotation, Hystrix will monitor the annotated method as ' ProductList ' (the bottom layer uses the proxy wrapper to implement this method to monitor), and once the error of this method accumulates to a certain threshold, the circuit breaker is started, All subsequent calls to the ' productlist ' method will fail, while the ' Fallbackmethod ' specified method ' Backupproductlist () ' is called temporarily, and then the breaker shuts down when the service returns to normal.
discoveryclient to find the URI address of the product service in this class, using the value of the product service's spring.application.name
configuration item, which is Product-service
as ServiceID
to discoveryclient.getinstances ()
method, and then returns a list, Because at the moment we only have one product service to start, so just take the URI address of the first instance.
Then we use the resttemplate
to access the API for the product service, note that the spring constructor injection is used, that is, the method that we used to @Bean
annotations is used to initialize the Resttemplate the
variable without our manual initialization. The resttemplate
class provides the Getforobject ()
method to access other rest APIs and wraps the result in the form of an object, the first parameter being 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 String.class
. The
backupproductlist ()
method returns the product listing 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;@RestControllerpublic class ProductController { @Autowired private ProductService productService; @RequestMapping("/products") public String productList() { return productService.productList(); }}
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