本文目录导读:

我为您提供一个完整的Spring Cloud Hystrix案例,包含服务提供者、服务消费者和熔断降级实现。
项目结构
hystrix-demo
├── pom.xml
├── service-provider
│ ├── pom.xml
│ └── src/main/java/com/example/provider
│ ├── ProviderApplication.java
│ └── controller/UserController.java
└── service-consumer
├── pom.xml
└── src/main/java/com/example/consumer
├── ConsumerApplication.java
├── controller/ConsumerController.java
├── service/UserService.java
└── service/fallback/UserServiceFallback.java
父POM配置 (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>com.example</groupId>
<artifactId>hystrix-demo</artifactId>
<version>1.0.0</version>
<packaging>pom</packaging>
<modules>
<module>service-provider</module>
<module>service-consumer</module>
</modules>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.3.12.RELEASE</version>
<relativePath/>
</parent>
<properties>
<java.version>1.8</java.version>
<spring-cloud.version>Hoxton.SR12</spring-cloud.version>
</properties>
<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>
</project>
服务提供者
1 提供者POM (service-provider/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>
<parent>
<groupId>com.example</groupId>
<artifactId>hystrix-demo</artifactId>
<version>1.0.0</version>
</parent>
<artifactId>service-provider</artifactId>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
</dependencies>
</project>
2 提供者启动类 (ProviderApplication.java)
package com.example.provider;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
@SpringBootApplication
@EnableDiscoveryClient
public class ProviderApplication {
public static void main(String[] args) {
SpringApplication.run(ProviderApplication.class, args);
}
}
3 提供者配置 (application.yml)
server:
port: 8081
spring:
application:
name: service-provider
eureka:
client:
service-url:
defaultZone: http://localhost:8761/eureka/
instance:
prefer-ip-address: true
4 用户控制器 (UserController.java)
package com.example.provider.controller;
import org.springframework.web.bind.annotation.*;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;
@RestController
@RequestMapping("/api/user")
public class UserController {
@GetMapping("/{id}")
public Map<String, Object> getUser(@PathVariable Long id) {
// 模拟正常响应
Map<String, Object> result = new HashMap<>();
result.put("id", id);
result.put("name", "用户" + id);
result.put("age", 20 + id.intValue());
result.put("service", "provider");
return result;
}
@GetMapping("/timeout")
public Map<String, Object> getUserWithTimeout() {
try {
// 模拟超时操作
TimeUnit.SECONDS.sleep(3);
} catch (InterruptedException e) {
e.printStackTrace();
}
Map<String, Object> result = new HashMap<>();
result.put("status", "success");
result.put("message", "响应时间3秒");
return result;
}
@GetMapping("/error")
public Map<String, Object> getUserWithError() {
// 模拟异常
throw new RuntimeException("服务异常");
}
}
服务消费者(包含Hystrix)
1 消费者POM (service-consumer/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>
<parent>
<groupId>com.example</groupId>
<artifactId>hystrix-demo</artifactId>
<version>1.0.0</version>
</parent>
<artifactId>service-consumer</artifactId>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<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-netflix-hystrix</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
</dependencies>
</project>
2 消费者启动类 (ConsumerApplication.java)
package com.example.consumer;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.circuitbreaker.EnableCircuitBreaker;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.openfeign.EnableFeignClients;
@SpringBootApplication
@EnableDiscoveryClient
@EnableCircuitBreaker
@EnableFeignClients
public class ConsumerApplication {
public static void main(String[] args) {
SpringApplication.run(ConsumerApplication.class, args);
}
}
3 消费者配置 (application.yml)
server:
port: 8082
spring:
application:
name: service-consumer
eureka:
client:
service-url:
defaultZone: http://localhost:8761/eureka/
instance:
prefer-ip-address: true
# Hystrix配置
hystrix:
command:
default:
execution:
isolation:
thread:
timeoutInMilliseconds: 4000
circuitBreaker:
requestVolumeThreshold: 10
errorThresholdPercentage: 50
sleepWindowInMilliseconds: 5000
getUserById:
execution:
isolation:
thread:
timeoutInMilliseconds: 2000
circuitBreaker:
requestVolumeThreshold: 5
errorThresholdPercentage: 50
sleepWindowInMilliseconds: 10000
# Feign开启Hystrix
feign:
hystrix:
enabled: true
4 Feign客户端接口 (UserClient.java)
package com.example.consumer.service;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import java.util.Map;
@FeignClient(name = "service-provider", fallback = UserServiceFallback.class)
public interface UserClient {
@GetMapping("/api/user/{id}")
Map<String, Object> getUserById(@PathVariable("id") Long id);
@GetMapping("/api/user/timeout")
Map<String, Object> getUserWithTimeout();
@GetMapping("/api/user/error")
Map<String, Object> getUserWithError();
}
5 降级处理类 (UserServiceFallback.java)
package com.example.consumer.service.fallback;
import com.example.consumer.service.UserClient;
import org.springframework.stereotype.Component;
import java.util.HashMap;
import java.util.Map;
@Component
public class UserServiceFallback implements UserClient {
@Override
public Map<String, Object> getUserById(Long id) {
Map<String, Object> fallback = new HashMap<>();
fallback.put("status", "fallback");
fallback.put("message", "获取用户信息失败,返回降级数据");
fallback.put("id", id);
fallback.put("name", "降级用户");
fallback.put("service", "fallback");
return fallback;
}
@Override
public Map<String, Object> getUserWithTimeout() {
Map<String, Object> fallback = new HashMap<>();
fallback.put("status", "fallback");
fallback.put("message", "请求超时,已触发降级");
return fallback;
}
@Override
public Map<String, Object> getUserWithError() {
Map<String, Object> fallback = new HashMap<>();
fallback.put("status", "fallback");
fallback.put("message", "服务异常,已触发降级");
return fallback;
}
}
6 服务类 (UserService.java)
package com.example.consumer.service;
import com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand;
import com.netflix.hystrix.contrib.javanica.annotation.HystrixProperty;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.HashMap;
import java.util.Map;
@Service
public class UserService {
@Autowired
private UserClient userClient;
/**
* 使用HystrixCommand注解(不用Feign的降级)
*/
@HystrixCommand(fallbackMethod = "getUserByIdFallback",
commandProperties = {
@HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds", value = "2000"),
@HystrixProperty(name = "circuitBreaker.requestVolumeThreshold", value = "10"),
@HystrixProperty(name = "circuitBreaker.errorThresholdPercentage", value = "50")
})
public Map<String, Object> getUserById(Long id) {
// 使用Feign调用
Map<String, Object> result = userClient.getUserById(id);
return result;
}
/**
* 降级方法
*/
public Map<String, Object> getUserByIdFallback(Long id) {
Map<String, Object> fallback = new HashMap<>();
fallback.put("status", "fallback");
fallback.put("message", "服务调用失败,使用本地降级方法");
fallback.put("id", id);
fallback.put("name", "本地降级");
return fallback;
}
/**
* 测试超时
*/
@HystrixCommand(fallbackMethod = "timeoutFallback")
public Map<String, Object> getUserWithTimeout() {
return userClient.getUserWithTimeout();
}
public Map<String, Object> timeoutFallback() {
Map<String, Object> fallback = new HashMap<>();
fallback.put("status", "fallback");
fallback.put("message", "超时降级");
return fallback;
}
/**
* 测试异常
*/
@HystrixCommand(fallbackMethod = "errorFallback")
public Map<String, Object> getUserWithError() {
return userClient.getUserWithError();
}
public Map<String, Object> errorFallback() {
Map<String, Object> fallback = new HashMap<>();
fallback.put("status", "fallback");
fallback.put("message", "异常降级");
return fallback;
}
/**
* 使用线程池隔离
*/
@HystrixCommand(groupKey = "UserGroup",
commandKey = "GetUserCommand",
threadPoolKey = "UserThreadPool",
threadPoolProperties = {
@HystrixProperty(name = "coreSize", value = "5"),
@HystrixProperty(name = "maxQueueSize", value = "10")
},
fallbackMethod = "getUserByIdFallback")
public Map<String, Object> getUserWithThreadPool(Long id) {
return userClient.getUserById(id);
}
}
7 消费者控制器 (ConsumerController.java)
package com.example.consumer.controller;
import com.example.consumer.service.UserClient;
import com.example.consumer.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import java.util.HashMap;
import java.util.Map;
@RestController
@RequestMapping("/consumer")
public class ConsumerController {
@Autowired
private UserService userService;
@Autowired
private UserClient userClient;
/**
* 通过Service调用(带降级)
*/
@GetMapping("/user/{id}")
public Map<String, Object> getUser(@PathVariable Long id) {
return userService.getUserById(id);
}
/**
* 测试超时场景
*/
@GetMapping("/test/timeout")
public Map<String, Object> testTimeout() {
long start = System.currentTimeMillis();
Map<String, Object> result = userService.getUserWithTimeout();
long end = System.currentTimeMillis();
Map<String, Object> response = new HashMap<>();
response.put("result", result);
response.put("time", (end - start) + "ms");
return response;
}
/**
* 测试异常场景
*/
@GetMapping("/test/error")
public Map<String, Object> testError() {
return userService.getUserWithError();
}
/**
* 测试线程池隔离
*/
@GetMapping("/test/thread-pool/{id}")
public Map<String, Object> testThreadPool(@PathVariable Long id) {
return userService.getUserWithThreadPool(id);
}
/**
* 直接通过Feign调用(使用Feign的降级)
*/
@GetMapping("/direct/user/{id}")
public Map<String, Object> directGetUser(@PathVariable Long id) {
return userClient.getUserById(id);
}
/**
* 健康检查端点
*/
@GetMapping("/health")
public Map<String, Object> health() {
Map<String, Object> health = new HashMap<>();
health.put("status", "UP");
health.put("service", "consumer");
return health;
}
}
测试用例
1 RestTemplate测试类
package com.example.consumer;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.web.client.TestRestTemplate;
import org.springframework.http.ResponseEntity;
import java.util.Map;
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
public class HystrixTest {
@Autowired
private TestRestTemplate restTemplate;
@Test
public void testGetUser() {
ResponseEntity<Map> response = restTemplate.getForEntity(
"/consumer/user/1", Map.class);
System.out.println("Response: " + response.getBody());
}
@Test
public void testTimeout() {
ResponseEntity<Map> response = restTemplate.getForEntity(
"/consumer/test/timeout", Map.class);
System.out.println("Timeout Response: " + response.getBody());
}
@Test
public void testError() {
ResponseEntity<Map> response = restTemplate.getForEntity(
"/consumer/test/error", Map.class);
System.out.println("Error Response: " + response.getBody());
}
}
运行说明
1 启动Eureka服务注册中心
# 需要先启动一个Eureka Server(端口8761)
2 启动服务提供者
cd service-provider mvn spring-boot:run # 访问 http://localhost:8081/api/user/1
3 启动服务消费者
cd service-consumer mvn spring-boot:run # 访问 http://localhost:8082/consumer/user/1
测试场景
- 正常调用:
http://localhost:8082/consumer/user/1 - 超时降级:
http://localhost:8082/consumer/test/timeout(等待3秒后降级) - 异常降级:
http://localhost:8082/consumer/test/error - 线程池隔离:
http://localhost:8082/consumer/test/thread-pool/1 - Feign降级:
http://localhost:8082/consumer/direct/user/1
Hystrix Dashboard监控(可选)
添加监控依赖和配置:
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-hystrix-dashboard</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
@SpringBootApplication
@EnableCircuitBreaker
@EnableHystrixDashboard
public class ConsumerApplication {
// ...
}
配置yml:
management:
endpoints:
web:
exposure:
include: hystrix.stream, health, info
这个完整的案例涵盖了:
- 服务提供者和消费者
- Feign集成Hystrix
- HystrixCommand注解方式
- 降级处理
- 超时设置
- 线程池隔离
- 熔断器配置