从浅入深 学习 SpringCloud 微服务架构(七)Hystrix(2)
一、Hystrix:基于 RestTemplate 的统一降级配置
1、Hystrix:基于 RestTemplate 的统一降级配置 步骤:
1)在项目的 pom.xml 配置文件中,引入 hystrix 依赖。
<!-- Hystrix 组件 对 RestTemplate 的支持4步:1)引入 Hystrix 依赖坐标 -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
</dependency>
2)在项目启动类中激活 hystrix
@SpringBootApplication
@EntityScan("djh.it.order.domain")
@EnableEurekaClient //激活 EurekaClient,同 @EnableDiscoveryClient 注解相同。
//@EnableFeignClients //激活 Feign
@EnableCircuitBreaker // Hystrix 组件 对 RestTemplate 的支持4步:2)激活 hystrix
public class OrderApplication { ... }
3)在项目的 Controller 类中,配置熔断触发的降级逻辑。
/**
* Hystrix:基于 RestTemplate 的统一降级配置:指定统一降级的方法,无参数。
* 注意:使用统一降级配置,需要返回类型保持一致。
* @return
*/
public Product defaultFallBack(){
Product product = new Product();
product.setProductName("触发 统一 降级方法 defaultFallBack");
return product;
}
4)在项目的 Controller 类中,在需要受到保护的接口上使用 @HystrixCommand 注解配置。
//@HystrixCommand(fallbackMethod = "orderFallBack")
@HystrixCommand //配置了公共的熔断设置后,就不需要传参数。
@RequestMapping(value = "/buy/{id}", method = RequestMethod.GET)
public Product findById(@PathVariable Long id){
Product product = null;
//product = restTemplate.getForObject("http://127.0.0.1:9001/product/1", Product.class);
product = restTemplate.getForObject("http://service-product/product/1", Product.class);
return product;
}
2、在服务消费者 order_service 子工程(子模块)中,修改 controller 类 OrderController.java,添加 Hystrix:基于 RestTemplate 的统一降级配置。
浏览器中安装一个插件,【Json 格式化工具】,将看上去杂乱无章的 Json 串转换为容易阅读的格式。
# Http 请求的 json 数据,显示的内容比较乱,难看懂,如何让它格式化显示?
/**
* spring_cloud_consul_demo\order_service\src\main\java\djh\it\order\controller\OrderController.java
*
* 2024-4-27 订单的 controller 类 OrderController.java
* 2024-4-28 修改,添加 Hystrix:基于 RestTemplate 的统一降级配置。
*/
package djh.it.order.controller;
import com.netflix.hystrix.contrib.javanica.annotation.DefaultProperties;
import com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand;
import djh.it.order.domain.Product;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;
@RestController
@RequestMapping("/order")
@DefaultProperties(defaultFallback = "defaultFallBack") //Hystrix:基于 RestTemplate 的统一降级配置,指定此接口中公共的熔断设置。
public class OrderController {
@Autowired // 注入 restTemplate 对象
private RestTemplate restTemplate;
/**
* Hystrix 组件 对 RestTemplate 的支持4步:4)使用注解配置熔断保护
* fallbackmethod : 配置熔断之后的降级方法
* @param id
* @return
*/
// @HystrixCommand(fallbackMethod = "orderFallBack")
@HystrixCommand //配置了公共的熔断设置后,就不需要传参数。
@RequestMapping(value = "/buy/{id}", method = RequestMethod.GET)
public Product findById(@PathVariable Long id){
Product product = null;
//product = restTemplate.getForObject("http://127.0.0.1:9001/product/1", Product.class);
product = restTemplate.getForObject("http://service-product/product/1", Product.class);
return product;
}
/**
* Hystrix 组件 对 RestTemplate 的支持4步:3)降级方法
* @param id
* @return
*/
public Product orderFallBack(Long id){
Product product = new Product();
product.setProductName("触发降级方法");
return product;
}
/**
* Hystrix:基于 RestTemplate 的统一降级配置:指定统一降级的方法,无参数。
* 注意:使用统一降级配置,需要返回类型保持一致。
* @return
*/
public Product defaultFallBack(){
Product product = new Product();
product.setProductName("触发 统一 降级方法 defaultFallBack");
return product;
}
}
3、重新运行 order_service, product_service, eureka_service 模块中,三个启动类,进行测试
1)浏览器地址栏输入:http://127.0.0.1:9000
发现 两个 服务,端口号分别是 9001.9002。
2)浏览器地址栏输入:http://127.0.0.1:9001/product/1
输出 mysql 数据库的第一条记录:
3)浏览器地址栏输入:http://localhost:9002/order/buy/1
输出如下:
4)模拟服务器宕机:如果访问的 service-product 服务器宕机,service-order 模块中,就会触发此降级方法。
把 服务提供者 product_service 模块中,启动类停止,再次访问测试,发现触发了降级方法。
浏览器地址栏输入:http://127.0.0.1:9002/order/buy/1
二、hystrix:基于 feign 调用的熔断配置。
1、在服务消费者 order_service 子工程(子模块)中,修改 启动类 添加 注解 @EnableFeignClients //激活 Feign 组件。
/**
* spring_cloud_demo\order_service\src\main\java\djh\it\order\OrderApplication.java
*
* 2024-4-27 启动类 OrderApplication.java
*/
package djh.it.order;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.domain.EntityScan;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
import org.springframework.cloud.openfeign.EnableFeignClients;
@SpringBootApplication
@EntityScan("djh.it.order.domain")
@EnableEurekaClient //激活 EurekaClient,同 @EnableDiscoveryClient 注解相同。
@EnableFeignClients //激活 Feign
//@EnableCircuitBreaker // 2)激活 hystrix, Hystrix 组件 对 RestTemplate 的支持4步:
public class OrderApplication {
//@EnableFeignClients //激活 Feign 组件后,不需要以下配置。
// @LoadBalanced
// @Bean
// public RestTemplate restTemplate(){
// return new RestTemplate();
// }
public static void main(String[] args) {
SpringApplication.run(OrderApplication.class, args);
}
}
2、在服务消费者 order_service 子工程(子模块)中,创建 调用 feign 组件的接口类 ProductFeignClient.java。
/**
* spring_cloud_demo\order_service\src\main\java\djh\it\order\feign\ProductFeignClient.java
*
* 2024-4-27 创建 调用 feign 组件的接口类 ProductFeignClient.java
* 声明需要调用的微服务名称 @FeignClient, name: 服务提供者的名称
*/
package djh.it.order.feign;
import djh.it.order.domain.Product;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
@FeignClient(name="service-product")
public interface ProductFeignClient {
//配置需要调用的微服务接口
@RequestMapping(value = "/product/{id}", method = RequestMethod.GET)
public Product findById(@PathVariable("id") Long id);
}
3、在服务消费者 order_service 子工程(子模块)中,修改 Controller 类 OrderController.java , 添加 注入 feign 组件的接口类 ProductFeignClient 并调用其方法。
/**
* spring_cloud_consul_demo\order_service\src\main\java\djh\it\order\controller\OrderController.java
*
* 2024-4-27 订单的 controller 类 OrderController.java
* 2024-4-27 第一次修改,添加 Hystrix:基于 RestTemplate 的统一降级配置。
* 2024-4-27 第二次修改,添加 hystrix:基于 feign 调用的熔断配置
*/
package djh.it.order.controller;
import com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand;
import djh.it.order.domain.Product;
import djh.it.order.feign.ProductFeignClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping("/order")
//@DefaultProperties(defaultFallback = "defaultFallBack") //Hystrix:基于 RestTemplate 的统一降级配置,指定此接口中公共的熔断设置。
public class OrderController {
@Resource //按类型名称注入 调用 feign 组件的接口类 ProductFeignClient
//@Autowired //自动注入 调用 feign 组件的接口类 ProductFeignClient //有时变量名报红,可替换为 @Resource 注解
private ProductFeignClient productFeignClient;
// @Autowired // 注入 restTemplate 对象
// private RestTemplate restTemplate;
/**
* Hystrix 组件 对 RestTemplate 的支持4步:4)使用注解配置熔断保护
* fallbackmethod : 配置熔断之后的降级方法
* @param id
* @return
*/
// @HystrixCommand(fallbackMethod = "orderFallBack")
@HystrixCommand //配置了公共的熔断设置后,就不需要传参数。
@RequestMapping(value = "/buy/{id}", method = RequestMethod.GET)
public Product findById(@PathVariable Long id){
Product product = null;
//product = restTemplate.getForObject("http://127.0.0.1:9001/product/1", Product.class);
//product = restTemplate.getForObject("http://service-product/product/1", Product.class);
//调用 feign 组件的接口类 的方法
product = productFeignClient.findById(id);
return product;
}
/**
* Hystrix 组件 对 RestTemplate 的支持4步:3)降级方法
* @param id
* @return
*/
// public Product orderFallBack(Long id){
// Product product = new Product();
// product.setProductName("触发降级方法");
// return product;
// }
/**
* Hystrix:基于 RestTemplate 的统一降级配置:指定统一降级的方法,无参数。
* 注意:使用统一降级配置,需要返回类型保持一致。
* @return
*/
// public Product defaultFallBack(){
// Product product = new Product();
// product.setProductName("触发 统一 降级方法 defaultFallBack");
// return product;
// }
}
4、Hystrix:基于 feign 调用的熔断配置 步骤:
1)在项目的 pom.xml 配置文件中,引入 hystrix 依赖。
<!-- Hystrix 组件 对 feign 调用 的支持4步:1)引入 Hystrix 依赖坐标 -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
</dependency>
2)在项目 的 application.yml 配置文件中,feign 配置中配置开启 Hystrix 。
feign:
client:
config:
service-product:
loggerLevel: FULL
hystrix: # 开启对 hystrix 的支持。
enabled: true
3)在项目中自定义一个 feign 接口的实现类,配置熔断触发的降级逻辑。
/**
* spring_cloud_sonsul_demo\order_service\src\main\java\djh\it\order\feign\ProductFeignClientCallBack.java
*
* 2024-4-27 创建 feign 组件的接口类 ProductFeignClient 的实现类 ProductFeignClientCallBack.java
* 配置熔断触发的降级逻辑。
*/
package djh.it.order.feign;
import djh.it.order.domain.Product;
import org.springframework.stereotype.Component;
@Component
public class ProductFeignClientCallBack implements ProductFeignClient{
@Override // 熔断降级的方法
public Product findById(Long id) {
Product product = new Product();
product.setProductName("hystrix:基于 feign 调用的熔断配置 -- feign 调用触发熔断降级的方法。");
return product;
}
}
4)在项目中修改 feignClient 接口,添加降级方法的支持。
@FeignClient(name="service-product", fallback = ProductFeignClientCallBack.class)
public interface ProductFeignClient {
//配置需要调用的微服务接口
@RequestMapping(value = "/product/{id}", method = RequestMethod.GET)
public Product findById(@PathVariable("id") Long id);
}
5、在服务消费者 order_service 子工程(子模块)pom.xml 配置文件中,引入 hystrix 依赖。此步骤可省略,因为 feign 中 集成了 hystrix 组件。
<?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">
<parent>
<artifactId>spring_cloud_consul_demo</artifactId>
<groupId>djh.it</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>order_service</artifactId>
<dependencies>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<!-- <version>5.1.32</version>-->
<version>8.0.26</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<!-- 导入 eureka 注册中心 -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<!-- springcloud 提供的对基于 consul 的服务发现 -->
<!-- <dependency>-->
<!-- <groupId>org.springframework.cloud</groupId>-->
<!-- <artifactId>spring-cloud-starter-consul-discovery</artifactId>-->
<!-- </dependency>-->
<!-- <!– actuator 健康检查 –>-->
<!-- <dependency>-->
<!-- <groupId>org.springframework.boot</groupId>-->
<!-- <artifactId>spring-boot-starter-actuator</artifactId>-->
<!-- </dependency>-->
<!-- springcloud 整合 openFeign -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
<!-- Hystrix 组件 对 RestTemplate 的支持4步:1)引入 Hystrix 依赖坐标 -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
</dependency>
</dependencies>
</project>
<!-- spring_cloud_consul_demo\order_service\pom.xml -->
6、在服务消费者 order_service 子工程(子模块)application.yml 配置文件中,引入 【feign 中配置开启 Hystrix 】。
## spring_cloud_consul_demo\order_service\src\main\resources\application.yml
server:
port: 9002 # 启动端口 命令行注入。
# port: ${port:9002} # 启动端口设置为动态传参,如果未传参数,默认端口为 9002
# tomcat:
# max-threads: 10 # 设置 tomcat 最大连接数量,用以模拟高并发环境问题。
spring:
application:
name: service-order #spring应用名, # 注意 FeignClient 不支持名字带下划线
# main:
# allow-bean-definition-overriding: true # SpringBoot2.1 需要设定。
datasource:
driver-class-name: com.mysql.jdbc.Driver # mysql 驱动
# url: jdbc:mysql://localhost:3306/shop?useUnicode=true&characterEncoding=utf8
url: jdbc:mysql://localhost:3306/shop?useUnicode=true&characterEncoding=utf8&useSSL=false&serverTimezone=Asia/Shanghai
# MySQL8.0 可以写成 root, 012311 或 'root', '012311' # MySQL5.7 只能写成 'root', '012311' # 注意用户名和密码后一定不能有空格。
username: 'root'
password: '12311'
jpa:
database: MySQL
show-sql: true
open-in-view: true
eureka: # 配置 Eureka
client:
service-url:
defaultZone: http://localhost:9000/eureka/ # 多个 eurekaserver 用 , 隔开。
instance:
prefer-ip-address: true # 使用 ip 地址注册
instance-id: ${spring.cloud.client.ip-address}:${server.port}
# 配置 feign 日志的输出。
# 日志配置:NONE:GI 不输出日志,BASIC:适用于生产环境追踪问题,HEADERS:在BASIC基础上,记录请求和响应头信息,FULL:记录所有。
feign:
client:
config:
default:
connectTimeout: 5000 #服务之间建立连接所用的时间 #不设置 connectTimeout 会导致 readTimeout 设置不生效
readTimeout: 5000 #建立连接后从服务端读取到数据用的时间
service-product: # 需要调用的服务名称
loggerLevel: FULL
hystrix: # 开启对 hystrix 的支持。
enabled: true
logging:
level:
djh.it.order.feign.ProductFeignClient: debug
#management: # 配置 Actuator 获取 hystrix 的监控数据 暴躁端点。
# endpoints:
# web:
# exposure:
# include: '*' # 暴露所有端点。
hystrix: # 配置 hystrix 熔断(Hystrix:基于 RestTemplate 的统一降级配置)
command:
default:
execution:
isolation:
thread:
timeoutInMilliseconds: 5000 # 默认的熔断超时时间为1秒,若1秒没有返回数据,会自动触发降级逻辑。
# # 配置 consul 的服务注册
# cloud:
# consul:
# host: 127.0.0.1 # consul 服务器的主机地址
# port: 8500 # consul 端口
# discovery:
# register: false # 是否需要注册,默认是 false
# instance-id: ${spring.application.name}-1 # 注册的实例 ID(唯一标志)
# service-name: ${spring.application.name} # 服务的名称
# port: ${server.port} # 服务的请求端口
# prefer-ip-address: true # 指定开启 IP 地址注册
# ip-address: ${spring.cloud.client.ip-address} # 当前服务的请求 IP
7、在服务消费者 order_service 子工程(子模块),创建 feign 组件的接口类 ProductFeignClient 的实现类 ProductFeignClientCallBack.java 配置熔断触发的降级逻辑。
/**
* spring_cloud_sonsul_demo\order_service\src\main\java\djh\it\order\feign\ProductFeignClientCallBack.java
*
* 2024-4-27 创建 feign 组件的接口类 ProductFeignClient 的实现类 ProductFeignClientCallBack.java
* 配置熔断触发的降级逻辑。
*/
package djh.it.order.feign;
import djh.it.order.domain.Product;
import org.springframework.stereotype.Component;
@Component
public class ProductFeignClientCallBack implements ProductFeignClient{
@Override // 熔断降级的方法
public Product findById(Long id) {
Product product = new Product();
product.setProductName("hystrix:基于 feign 调用的熔断配置 -- feign 调用触发熔断降级的方法。");
return product;
}
}
8、在服务消费者 order_service 子工程(子模块)feign 组件的接口类 ProductFeignClient.java 中,添加降级方法的支持,配置熔断触发的降级逻辑。
/**
* spring_cloud_demo\order_service\src\main\java\djh\it\order\feign\ProductFeignClient.java
*
* 2024-4-27 创建 调用 feign 组件的接口类 ProductFeignClient.java
* 声明需要调用的微服务名称 @FeignClient, name: 服务提供者的名称, fallback:配置熔断发生的降级方法。
*/
package djh.it.order.feign;
import djh.it.order.domain.Product;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
@FeignClient(name="service-product", fallback = ProductFeignClientCallBack.class) //添加降级方法的支持
public interface ProductFeignClient {
//配置需要调用的微服务接口
@RequestMapping(value = "/product/{id}", method = RequestMethod.GET)
public Product findById(@PathVariable("id") Long id);
}
9、重新运行 eureka_service, product_service, order_service, 三个启动类,进行测试
1)浏览器地址栏输入:http://127.0.0.1:9000
发现 两个 服务,端口号分别是 9001.9002。
2)浏览器地址栏输入:http://127.0.0.1:9001/product/1
正常输出 mysql 数据库的第一条记录:
3)浏览器地址栏输入:http://localhost:9002/order/buy/1
正常输出 mysql 数据库的第一条记录:
4)重新运行 eureka_service, order_service, 不启动 product_service 模块(停掉),进行测试
浏览器地址栏输入:http://localhost:9002/order/buy/1
会触发熔断器,输出熔断提示如下:
上一节链接请点击:
# 从浅入深 学习 SpringCloud 微服务架构(七)Hystrix(1)