1. 新建 moudle : hystrix-consumer
服务提供者依然是 eureka-client
Pom.xml 依赖中引入 spring-cloud-starter-netflix-hystrix
<dependencies>
<dependency>
<!-- eureka 最核心的依赖 从顶层项目中的 dependencyManagement 中获取版本-->
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-actuator</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
</dependency>
</dependencies>
2. Application 启动类 添加 注解 :
@EnableCircuitBreaker
@SpringBootApplication
@EnableDiscoveryClient //DiscoveryClient 发现服务的意思,就是需要到注册中心拉取服务列表
@EnableFeignClients
@EnableCircuitBreaker // 开启断路器
public class HystrixConsumerApplication {
3. 创建 Fallback 类
在以往的 Feign 调用中,都是在 Controller 调用 interface ,如果Feign调用出现异常、超时情况,需要有个类来做这些处理。
创建一个 Fallback 类 实现 接口,当Feign调用出现异常、超时情况,就会执行 Fallback 类 对应的调用 的降级方法。
@Component
public class Fallback implements HystrixProducerService {
@Override
public String hystrix(int time) {
System.err.println("fallback 降级策略");
return "fallback 降级策略";
}
@Override
public String hystrixTimeOut(int time) {
System.err.println("fallback 超时咯.... "+ time);
return "you are late !!! ";
}
@FeignClient 注解中,指定降级类名是 fallback = Fallback.class
@FeignClient(value = "eureka-client",fallback = Fallback.class)
public interface HystrixProducerService {
/**
* 用于测试 hystrix 熔断、降级
* @return
*/
@GetMapping("/hystrix/{time}")
public String hystrix(@PathVariable("time") int time);
/**
* 用于测试 hystrix 超时
* @param time
* @return
*/
@GetMapping("/hystrixout/{time}")
public String hystrixTimeOut(@PathVariable("time") int time);
Controller 中还是和之前项目一样调用
@RestController
public class ConsumerController {
@Autowired
HystrixProducerService service;
@GetMapping("/hystrix/{time}")
public String hystrix(@PathVariable("time") int time) throws InterruptedException {
System.err.println( "------ time : "+time );
return service.hystrix(time);
}
/**
* 测试 hystrix 超时, 降级方法
* @param time
* @return
* @throws InterruptedException
*/
@GetMapping("/hystrixout/{time}")
public String hystrixTimeOut(@PathVariable("time") int time) throws InterruptedException {
System.err.println( "------ time : "+time );
return service.hystrixTimeOut (time);
}
@GetMapping("/hi")
public String hi(){
return service.sayHi();
}
application.properties 配置
【注意】 Ribbon 也有超时配置,Feign调用会影响Hystrix 的超时配置。 在这个Demo中先把Ribbon的超时配置调大,先来测试 Hystrix 的超时配置是否生效。
server.port=9880
spring.application.name=hystrix-consumer
eureka.client.serviceUrl.defaultZone=http://eureka1:8860/eureka
## 是否需要引入IP。 就是这个 服务注册到 eureka 注册中心后,而显示 这个ip
eureka.instance.prefer-ip-address=true
## 这里可以写个表达式 .这两行意思就是注册到注册中心后显示 自己的ip地址
eureka.instance.instance-id=${spring.application.name}: ${eureka.instance.ip-address}:${server.port}
# 允许bean定义上的重载
#spring.main.allow-bean-definition-overriding=true
# ---------------------- Feign & Hystrix 配置--------------------------
# 开启 Feign 下面的 hystrix 功能
feign.hystrix.enabled=true
# 是否开启服务降级(默认开启)
hystrix.command.default.fallback.enabled=true
# Hystrix 全局超时
hystrix.command.default.execution.timeout.enable=true
# 超时时间 2 秒
hystrix.command.default.execution.isolation.thread.timeoutInMilliseconds=2000
# 超时以后终止线程
hystrix.command.default.execution.isolation.thread.interruptOnTimeout=true
# 取消的时候终止线程
hystrix.command.default.execution.isolation.thread.interruptOnFutureCancel=true
# 单独设置某个方法的超时时间,覆盖全局超时时间。HystrixProducerService#hystrixTimeOut(int) 是方法签名。是指定要配置的哪个方法
hystrix.command.HystrixProducerService#hystrixTimeOut(int).execution.isolation.thread.timeoutInMilliseconds=3000
#【注意:eureka-client 是服务名。 在这里作为服务提供者,被调用】
# 每台机器最大重试次数。 第一次连过去,失败,还能重试两次。相当于总共连接3次
eureka-client.ribbon.MaxAutoRetries=0
# 可以再重试几台机器。
eureka-client.ribbon.MaxAutoRetriesNextServer=0
# 连接超时; 1.建立连接
eureka-client.ribbon.ConnectTimeout=8000
# 业务处理超时 2.业务处理
eureka-client.ribbon.ReadTimeout=9000
# 在 所有 Http Method 进行重试。 默认是 false. 【谨慎开启】 ,否则 delete , update , insert 操作需要做幂等
eureka-client.ribbon.OkToRetryOnAllOperations=true
Hystrix 可以配置全局的超时时间,当然也可以配置指定某个方法的超时时间
# 单独设置某个方法的超时时间,覆盖全局超时时间。HystrixProducerService#hystrixTimeOut(int) 是方法签名。是指定要配置的哪个方法
hystrix.command.HystrixProducerService#hystrixTimeOut(int).execution.isolation.thread.timeoutInMilliseconds=3000
1. 在properties 中配置某个方法的超时时间
2. 在代码中使用注解 @HystrixCommand(commandKey = "11223") 设定key=11223的超时时间
hystrix.command.11223.execution.isolation.thread.timeoutInMilliseconds=3000
4. 附上 provider eureka-client 的 controller
@RestController
@Slf4j
public class ProviderController {
@Value("${server.port}")
private String port;
@GetMapping("/hi")
public String hi(){
return "This is "+ port;
}
/**
* Feign 测试用接口。 测试feing 的连接、读 超时后的配置是否起作用。
* 【结果 OK】
* @param time
* @return
* @throws InterruptedException
*/
@GetMapping("/feign/{time}")
public String feign(@PathVariable("time") int time) throws InterruptedException {
System.out.println(" time : " +time +" port: "+port);
Thread.sleep(time);
return "This is "+ port +" / " + time;
}
/**
* 用于 hystrix 测试熔断降级
* @param time
* @return
* @throws InterruptedException
*/
@GetMapping("/hystrix/{time}")
public String hystrix(@PathVariable("time") int time)throws InterruptedException{
System.out.println("------------------- time1 : " +time +" port: "+port);
if(time < 800){
throw new RuntimeException("抛出异常咯..... ");
}
System.out.println("------------------- time2 : " +time +" port: "+port);
Thread.sleep(time);
return port;
}
@GetMapping("/hystrixout/{time}")
public String hystrixTimeOut(@PathVariable("time") int time)throws InterruptedException{
System.out.println("------------------- time2 : " +time +" port: "+port);
Thread.sleep(time);
return port;
}
}
至此, 调用 hystix-consumer 的 接口,可以测试 hystrix的降级、超时。
获取方法签名
public static void main(String[] args) throws NoSuchMethodException {
System.out.println(Feign.configKey(HystrixProducerService.class,
HystrixProducerService.class.getMethod("hystrixTimeOut",int.class)
// 方法名 入参类型
));
控制台打印:
HystrixProducerService#hystrixTimeOut(int)