线程隔离示意图:
解读:
Hystrix为每个依赖服务调用分配一个小的线程池,如果线程池已满调用将被立即拒绝,默认不采用排队,加速失败判定时间。
快速入门:
(都是在consumer-demo改)
都是基于上一篇博客的代码:https://blog.csdn.net/GLOAL_COOK/article/details/114272205
1)引入依赖
在 consumer-demo 消费端系统的pom.xml文件添加如下依赖:
(版本不对应可能爆错,我的springboot是2.4.3没错)
<!--Hystrix线程隔离-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
<version>2.1.3.RELEASE</version>
</dependency>
2)开启熔断
在启动类 ConsumerApplication 上添加注解:@EnableHystrix
3)编写降级逻辑
当目标服务的调用出现故障,我们希望快速失败,给用户一个友好提示。因此需要提前编写好失败时的降级处理逻辑,要使用HystrixCommand来完成。改造 consumer-demo\src\main\java\com\itheima\consumer\controller\ConsumerController.java 处理器
类,如下:
package com.itheima.consumer.controller;
import com.itheima.consumer.pojo.User;
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.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;
import java.util.List;
/**
* @author QLBF
* @version 1.0
* @date 2021/3/1 23:12
*/
@RestController
@RequestMapping("/consumer")
public class ConsumerController {
@Autowired
private RestTemplate restTemplate;
@Autowired
private DiscoveryClient discoveryClient;
@GetMapping("{id}")
//这是指定下面那个降级方法
@HystrixCommand(fallbackMethod ="queryByIdFallback")
public User queryById(@PathVariable Long id){
/*
//String url="http://localhost:9091/user/"+id;
//获取eureka中注册的user-service实例列表,这里写的user-service要和user-service工程里面application.yml定义的应用名一致
List<ServiceInstance> serviceInstances = discoveryClient.getInstances("user-service");
ServiceInstance serviceInstance = serviceInstances.get(0);//获取服务列表的第一个(0是第一个,一般一个服务一个)的意思,得根据你服务列表有多少
String url = "http://" + serviceInstance.getHost() + ":" + serviceInstance.getPort() + "/user/" + id;
*/
//负载均衡Ribbon的url方式,简单很多:
String url="http://user-service/user/"+id;
return restTemplate.getForObject(url,User.class);
}
/*降级方法
和需要收到保护的方法的返回值一致
方法参数一致*/
public User queryByIdFallback(Long id){
User user=new User();
user.setUserName("触发降级方法了");
return user;
}
}
原本:
要注意;因为熔断的降级逻辑方法必须跟正常逻辑方法保证:相同的参数列表和返回值声明。
测试:
当 user-service 正常提供服务时,访问与以前一致如上图。但是当将 user-service 停机时,会发现页面返回了降级处理信息:
4)默认的Fallback(还是用第三点好,在方法上加好)
刚才把fallback写在了某个业务方法上,如果这样的方法很多,那岂不是要写很多。所以可以把Fallback配置加在类上,实现默认fallback;再次改造 consumer-demo\src\main\java\com\itheima\consumer\controlle\ConsumerController.java:
package com.itheima.consumer.controller;
import com.itheima.consumer.pojo.User;
import com.netflix.hystrix.contrib.javanica.annotation.DefaultProperties;
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.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;
import java.util.List;
/**
* @author QLBF
* @version 1.0
* @date 2021/3/1 23:12
*/
@RestController
//2.统一的降低方法
@DefaultProperties(defaultFallback = "defaultFallback")
@RequestMapping("/consumer")
public class ConsumerController {
@Autowired
private RestTemplate restTemplate;
@Autowired
private DiscoveryClient discoveryClient;
@GetMapping("{id}")
//1.在方法上的降低方法,这是指定下面那个降级方法
//@HystrixCommand(fallbackMethod ="queryByIdFallback")
@HystrixCommand //就算是统一的方法也得加上
public User queryById(@PathVariable Long id){
/*
//String url="http://localhost:9091/user/"+id;
//获取eureka中注册的user-service实例列表,这里写的user-service要和user-service工程里面application.yml定义的应用名一致
List<ServiceInstance> serviceInstances = discoveryClient.getInstances("user-service");
ServiceInstance serviceInstance = serviceInstances.get(0);//获取服务列表的第一个(0是第一个,一般一个服务一个)的意思,得根据你服务列表有多少
String url = "http://" + serviceInstance.getHost() + ":" + serviceInstance.getPort() + "/user/" + id;
*/
//负载均衡Ribbon的url方式,简单很多:
String url="http://user-service/user/"+id;
return restTemplate.getForObject(url,User.class);
}
/*降级方法
和需要收到保护的方法的返回值一致
方法参数一致*/
public User queryByIdFallback(Long id){
User user=new User();
user.setUserName("触发降级方法了");
return user;
}
/*
统一的降级方法
和需要上面所以的方法的返回值一致
方法参数要为空*/
public User defaultFallback(){
User user=new User();
user.setUserName("触发统一的降级方法了");
return user;
}
}
```![在这里插入图片描述](https://img-blog.csdnimg.cn/20210303113536263.png)
再停掉user-service:
![在这里插入图片描述](https://img-blog.csdnimg.cn/20210303113521765.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L0dMT0FMX0NPT0s=,size_16,color_FFFFFF,t_70)
测试成功!![在这里插入图片描述](https://img-blog.csdnimg.cn/20210303113624402.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L0dMT0FMX0NPT0s=,size_16,color_FFFFFF,t_70)
就不演示了