点击下载教程项目代码:
netflix_hystrix_demo.zip
本章我们将通过一个简单的实例来介绍 Hystrix 的具体用法,该实例基于“Netflix Hystrix 准备工作”章节提供的服务。
在使用 Hystrix 之前,我们需要先添加 maven 依赖。项目完整 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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.2.11.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.hxstrive</groupId>
<artifactId>hystrix-demo</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>hystrix-demo</name>
<description>hystrix-demo</description>
<properties>
<java.version>8</java.version>
<spring-cloud.version>Hoxton.SR8</spring-cloud.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
<!-- spring cloud 依赖 -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<!-- hystrix依赖 -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.83</version>
</dependency>
</dependencies>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>${spring-cloud.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<build>
<finalName>service-demo</finalName>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.1</version>
<configuration>
<source>8</source>
<target>8</target>
</configuration>
</plugin>
</plugins>
</build>
</project>添加 application.yml 配置文件,在该配置文件中配置注册中心地址。内容如下:
server: port: 8080 spring: application: name: hystrix-demo ## 服务地址 eureka: client: enabled: true service-url: # 注册中心路径,表示我们向这个注册中心注册服务,如果向多个注册中心注册,用“,”进行分隔 defaultZone: http://localhost:8761/eureka instance: hostname: localhost # 心跳间隔5s,默认30s。每一个服务配置后,心跳间隔和心跳超时时间会被保存在server端, # 不同服务的心跳频率可能不同,server端会根据保存的配置来分别探活 lease-renewal-interval-in-seconds: 5 # 心跳超时时间10s,默认90s。从client端最后一次发出心跳后, # 达到这个时间没有再次发出心跳,表示服务不可用,将它的实例从注册中心移除 lease-expiration-duration-in-seconds: 10 logging: level: root: info # 设置 RestTemplate 日志级别为 DEBUG org.springframework.web.client.RestTemplate: DEBUG
添加 RestTemplate 配置,并且在该 restTemplate() 上面添加 @LoadBalanced 注解。开启负载均衡策略功能,代码如下:
package com.hxstrive.hystrix_demo.config;
import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.client.RestTemplate;
/**
* RestTemplate 配置类
* @author hxstrive.com
*/
@Configuration
public class RestTemplateConfig {
// 配置一个 RestTemplate
@Bean
// 添加该注解后,可以使得 RestTemplate 拥有负载均衡能力
@LoadBalanced
public RestTemplate restTemplate() {
return new RestTemplate();
}
}启动类是一个简单的 Spring Boot 启动类,但是该类使用 @EnableCircuitBreaker 注解开启断路器功能。代码如下:
package com.hxstrive.hystrix_demo;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.circuitbreaker.EnableCircuitBreaker;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
/**
* 入库类
* @author hxstrive.com
*/
@RestController
@SpringBootApplication
// 启用断路器
@EnableCircuitBreaker
public class HystrixDemoApplication {
@Value("${spring.application.name}")
private String appName;
@Value("${server.port}")
private String appPort;
public static void main(String[] args) {
SpringApplication.run(HystrixDemoApplication.class, args);
}
@GetMapping("/")
public String index() {
return "appName=" + appName + ", appPort=" + appPort;
}
}一个简单的控制器,提供 /demo1/getAllUsers 方法,该方法调用 UserService 服务的服务,然后调用远程服务。代码如下:
package com.hxstrive.hystrix_demo.controller;
import com.hxstrive.hystrix_demo.dto.CommonReturn;
import com.hxstrive.hystrix_demo.entity.User;
import com.hxstrive.hystrix_demo.service.UserService;
import com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.List;
/**
* 简单控制器
* @author hxstrive.com
*/
@RestController
@RequestMapping("/demo1")
public class Demo1Controller {
@Autowired
private UserService userService;
@GetMapping("/getAllUsers")
@HystrixCommand(fallbackMethod = "fallback")
public CommonReturn<List<User>> getAllUsers() {
return userService.getAllUsers();
}
/**
* 当服务调用失败时,调用此方法
*/
private CommonReturn<List<User>> fallback() {
return CommonReturn.fail("网络出现问题,调用 fallback 方法");
}
}用户服务类,通过服务名(见 Eureka)调用实际服务,代码如下:
package com.hxstrive.hystrix_demo.service;
import com.alibaba.fastjson.JSONObject;
import com.hxstrive.hystrix_demo.dto.CommonReturn;
import com.hxstrive.hystrix_demo.entity.User;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.ParameterizedTypeReference;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpMethod;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;
import java.util.List;
/**
* 用户服务
* @author hxstrive.com
* @since 1.0.0 2024/11/13 15:20
*/
@Service
public class UserService {
@Autowired
private RestTemplate restTemplate;
public CommonReturn<List<User>> getAllUsers() {
// 如果你要实现负载均衡,调用地址不能写具体主机地址
// 需要将主机地址替换成对于服务的服务名,即 spring.application.name 指定的值
// 你也可以到 Eureka server 中去查看
String url = "http://SERVICE-DEMO/user/getAllUsers";
// 使用 ParameterizedTypeReference 来保留泛型信息
ParameterizedTypeReference<CommonReturn<List<User>>> typeRef = new ParameterizedTypeReference<CommonReturn<List<User>>>() {};
ResponseEntity<CommonReturn<List<User>>> responseEntity = restTemplate.exchange(url, HttpMethod.GET, null, typeRef);
return responseEntity.getBody();
}
// 调用根据用户ID获取用户信息的接口
public CommonReturn<User> getUserById(Long id) {
String url = "http://SERVICE-DEMO/user/getUserById?id=" + id;
// 使用 ParameterizedTypeReference 来保留泛型信息
ParameterizedTypeReference<CommonReturn<User>> typeRef = new ParameterizedTypeReference<CommonReturn<User>>() {};
ResponseEntity<CommonReturn<User>> responseEntity = restTemplate.exchange(url, HttpMethod.GET, null, typeRef);
return responseEntity.getBody();
}
// 调用创建新用户的接口
public CommonReturn<User> createUser(User user) {
String url = "http://SERVICE-DEMO/user/createUser";
HttpEntity<User> requestEntity = new HttpEntity<>(user);
// 使用 ParameterizedTypeReference 来保留泛型信息
ParameterizedTypeReference<CommonReturn<User>> typeRef = new ParameterizedTypeReference<CommonReturn<User>>() {};
ResponseEntity<CommonReturn<User>> responseEntity = restTemplate.exchange(url, HttpMethod.POST, requestEntity, typeRef);
return responseEntity.getBody();
}
// 调用更新用户信息的接口
public CommonReturn<User> updateUser(Long id, User updatedUser) {
String url = "http://SERVICE-DEMO/user/updateUser?id=" + id;
HttpEntity<User> requestEntity = new HttpEntity<>(updatedUser);
// 使用 ParameterizedTypeReference 来保留泛型信息
ParameterizedTypeReference<CommonReturn<User>> typeRef = new ParameterizedTypeReference<CommonReturn<User>>() {};
ResponseEntity<CommonReturn<User>> responseEntity = restTemplate.exchange(url, HttpMethod.PUT, requestEntity, typeRef);
return responseEntity.getBody();
}
// 调用删除用户的接口
public CommonReturn<String> deleteUser(Long id) {
String url = "http://SERVICE-DEMO/user/deleteUser?id=" + id;
// 使用 ParameterizedTypeReference 来保留泛型信息
ParameterizedTypeReference<CommonReturn<String>> typeRef = new ParameterizedTypeReference<CommonReturn<String>>() {};
ResponseEntity<CommonReturn<String>> responseEntity = restTemplate.exchange(url, HttpMethod.DELETE, null, typeRef);
return responseEntity.getBody();
}
}通用返回对象实体,代码如下:
package com.hxstrive.hystrix_demo.dto;
import lombok.Data;
/**
* 通用返回对象
* @author hxstrive.com
*/
@Data
public class CommonReturn<T> {
private int code;
private String message;
private T data;
private String appName;
private String port;
public static <T> CommonReturn<T> success(T data) {
CommonReturn<T> commonReturn = new CommonReturn<>();
commonReturn.setCode(1);
commonReturn.setData(data);
return commonReturn;
}
public static <T> CommonReturn<T> success() {
return success(null);
}
public static <T> CommonReturn<T> fail(String message) {
CommonReturn<T> commonReturn = new CommonReturn<>();
commonReturn.setCode(0);
commonReturn.setMessage(message);
return commonReturn;
}
public CommonReturn<T> ext(String appName, String port) {
this.setAppName(appName);
this.setPort(port);
return this;
}
}用户实体类,代码如下:
package com.hxstrive.hystrix_demo.entity;
import lombok.Builder;
import lombok.Data;
import lombok.ToString;
/**
* 用户实体
* @author hxstrive.com
*/
@Data
@Builder
@ToString
public class User {
private Long id;
private String name;
private Integer age;
public User() {}
public User(Long id, String name, Integer age) {
this.id = id;
this.name = name;
this.age = age;
}
}此时,启动 HystrixEurekaServerApplication、HystrixServiceUserApplication 和 HystrixDemoApplication 服务,成功启动后服务状态如下图:

此时,浏览器访问 http://localhost:8080/demo1/getAllUsers 地址,效果如下图:

如果我们尝试将“HystrixServiceUserApplication”服务停止,再次访问 http://localhost:8080/demo1/getAllUsers 地址,效果如下图:

通过上图,已经触发了 @HystrixCommand(fallbackMethod = "fallback") 注解 fallbackMethod 方法配置的 fallback 方法。fallback 方法代码如下:
/**
* 当服务调用失败时,调用此方法
*/
private CommonReturn<List<User>> fallback() {
return CommonReturn.fail("网络出现问题,调用 fallback 方法");
}