1. 回顾

  上文讲解了使用注解@HystrixCommand的fallbackMethod属性实现回退。然而,Feign是以接口形式工作的,

它没有方法体,前文讲解的方式显然不适用与Feign。

  事实上,Spring Cloud默认已为Feign整合了Hystrix,只要Hystrix在项目的classpath中,Feign默认就会用

断路器包裹所有方法。

2. 为Feign添加回退

  > 复制项目 microservice-consumer-movie-feign ,将 ArtifactId 修改为 microservice-consumer-movie-feign-hystrix-fallback

  > 将之前编写的Feign接口修改为如下内容:

package com.itmuch.cloud.microserviceconsumermoviefeignhystrixfallback.feign;

import com.itmuch.cloud.microserviceconsumermoviefeignhystrixfallback.pojo.User;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.stereotype.Component;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable; /**
* Feign的fallback测试类
* 使用@FeignClient的fallback属性指定回退类
*/
@FeignClient(name = "microservice-provider-user", fallback = FeignClientFallback.class)
public interface UserFeignClient { @GetMapping(value = "/{id}")
User findById(@PathVariable("id") Long id); } /**
* 回退类FeignClientFallback需实现Feign Client接口
* FeignClientFallback也可以是public class,没有区别
*/
@Component
class FeignClientFallback implements UserFeignClient { @Override
public User findById(Long id) {
User user = new User();
user.setId(-1L);
user.setUsername("默认用户");
return user;
}
}

  > 修改 application.yml 文件,声明 Feign 的 Hystrix 支持

feign:
hystrix:
enabled: true

  > 启动 microservice-discovery-eureka

  > 启动 microservice-provider-user

  > 启动 microservice-consumer-movie-feign-hystrix-fallback

  > 访问 http://localhost:8010/user/1 ,可正常获取结果

  > 停止 microservice-provider-user

  > 访问 http://localhost:8010/user/1 ,可获取回退方法里返回的结果

3. 通过Fallback Factory检查回退原因

  > 复制项目 microservice-consumer-movie-feign,将 ArtifactId 修改为 microservice-consumer-movie-feign-hystrix-fallback-factory

  > 修改 UserFeignClient.java 为如下内容

package com.itmuch.cloud.microserviceconsumermoviefeignhystrixfallbackfactory.feign;

import com.itmuch.cloud.microserviceconsumermoviefeignhystrixfallbackfactory.pojo.User;
import feign.hystrix.FallbackFactory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.stereotype.Component;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable; @FeignClient(name = "microservice-provider-user", fallbackFactory = FeignClientFallbackFactory.class)
public interface UserFeignClient { @GetMapping(value = "/{id}")
User findById(@PathVariable("id") Long id); } /**
* UserFeignClient的fallbackFactory类,该类需要实现FallbackFactory接口,并覆写create方法
*/
@Component
class FeignClientFallbackFactory implements FallbackFactory<UserFeignClient> { private static final Logger LOGGER = LoggerFactory.getLogger(FeignClientFallbackFactory.class); @Override
public UserFeignClient create(Throwable throwable) {
// 下方匿名方法的Lambda表达式。>= JDK8
return (id) -> {
// 日志最好放在各个fallback方法中,而不要直接放在create方法中。
// 否则在引用启动时,就会打印该日志
FeignClientFallbackFactory.LOGGER.info("fallback; reason was: ", throwable);
User user = new User();
user.setId(-1L);
user.setUsername("默认用户");
return user;
}; /* return new UserFeignClient() {
@Override
public User findById(Long id) {
// 日志最好放在各个fallback方法中,而不要直接放在create方法中。
// 否则在引用启动时,就会打印该日志
FeignClientFallbackFactory.LOGGER.info("fallback; reason was: ", throwable);
User user = new User();
user.setId(-1L);
user.setUsername("默认用户");
return user;
}
};*/
} }

  > 修改 application.yml 文件,声明 Feign 的 Hystrix 支持

feign:
hystrix:
enabled: true

  > 跟上方测试方法一样。此次调用回退方法时,控制台会打出错误日志

2018-06-07 13:55:31.716  INFO 5188 --- [provider-user-1] c.i.c.m.f.FeignClientFallbackFactory     : fallback; reason was: 

java.lang.RuntimeException: com.netflix.client.ClientException: Load balancer does not have available server for client: microservice-provider-user
at org.springframework.cloud.openfeign.ribbon.LoadBalancerFeignClient.execute(LoadBalancerFeignClient.java:71) ~[spring-cloud-openfeign-core-2.0.0.M1.jar:2.0.0.M1]
at feign.SynchronousMethodHandler.executeAndDecode(SynchronousMethodHandler.java:97) ~[feign-core-9.5.1.jar:na]
at feign.SynchronousMethodHandler.invoke(SynchronousMethodHandler.java:76) ~[feign-core-9.5.1.jar:na]
at feign.hystrix.HystrixInvocationHandler$1.run(HystrixInvocationHandler.java:108) ~[feign-hystrix-9.5.1.jar:na]
at com.netflix.hystrix.HystrixCommand$2.call(HystrixCommand.java:302) ~[hystrix-core-1.5.12.jar:1.5.12]
at com.netflix.hystrix.HystrixCommand$2.call(HystrixCommand.java:298) ~[hystrix-core-1.5.12.jar:1.5.12]
at rx.internal.operators.OnSubscribeDefer.call(OnSubscribeDefer.java:46) ~[rxjava-1.3.6.jar:1.3.6]
at rx.internal.operators.OnSubscribeDefer.call(OnSubscribeDefer.java:35) ~[rxjava-1.3.6.jar:1.3.6]
at rx.internal.operators.OnSubscribeLift.call(OnSubscribeLift.java:48) [rxjava-1.3.6.jar:1.3.6]
at rx.internal.operators.OnSubscribeLift.call(OnSubscribeLift.java:30) [rxjava-1.3.6.jar:1.3.6]
at rx.internal.operators.OnSubscribeLift.call(OnSubscribeLift.java:48) [rxjava-1.3.6.jar:1.3.6]
at rx.internal.operators.OnSubscribeLift.call(OnSubscribeLift.java:30) [rxjava-1.3.6.jar:1.3.6]
at rx.internal.operators.OnSubscribeLift.call(OnSubscribeLift.java:48) [rxjava-1.3.6.jar:1.3.6]
at rx.internal.operators.OnSubscribeLift.call(OnSubscribeLift.java:30) [rxjava-1.3.6.jar:1.3.6]
at rx.Observable.unsafeSubscribe(Observable.java:10256) [rxjava-1.3.6.jar:1.3.6]
at rx.internal.operators.OnSubscribeDefer.call(OnSubscribeDefer.java:51) ~[rxjava-1.3.6.jar:1.3.6]
at rx.internal.operators.OnSubscribeDefer.call(OnSubscribeDefer.java:35) ~[rxjava-1.3.6.jar:1.3.6]
at rx.Observable.unsafeSubscribe(Observable.java:10256) [rxjava-1.3.6.jar:1.3.6]
at rx.internal.operators.OnSubscribeDoOnEach.call(OnSubscribeDoOnEach.java:41) [rxjava-1.3.6.jar:1.3.6]
at rx.internal.operators.OnSubscribeDoOnEach.call(OnSubscribeDoOnEach.java:30) [rxjava-1.3.6.jar:1.3.6]
at rx.internal.operators.OnSubscribeLift.call(OnSubscribeLift.java:48) [rxjava-1.3.6.jar:1.3.6]
at rx.internal.operators.OnSubscribeLift.call(OnSubscribeLift.java:30) [rxjava-1.3.6.jar:1.3.6]
at rx.Observable.unsafeSubscribe(Observable.java:10256) [rxjava-1.3.6.jar:1.3.6]
at rx.internal.operators.OperatorSubscribeOn$SubscribeOnSubscriber.call(OperatorSubscribeOn.java:100) [rxjava-1.3.6.jar:1.3.6]
at com.netflix.hystrix.strategy.concurrency.HystrixContexSchedulerAction$1.call(HystrixContexSchedulerAction.java:56) [hystrix-core-1.5.12.jar:1.5.12]
at com.netflix.hystrix.strategy.concurrency.HystrixContexSchedulerAction$1.call(HystrixContexSchedulerAction.java:47) [hystrix-core-1.5.12.jar:1.5.12]
at com.netflix.hystrix.strategy.concurrency.HystrixContexSchedulerAction.call(HystrixContexSchedulerAction.java:69) [hystrix-core-1.5.12.jar:1.5.12]
at rx.internal.schedulers.ScheduledAction.run(ScheduledAction.java:55) [rxjava-1.3.6.jar:1.3.6]
at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511) [na:1.8.0_161]
at java.util.concurrent.FutureTask.run(FutureTask.java:266) [na:1.8.0_161]
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149) [na:1.8.0_161]
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624) [na:1.8.0_161]
at java.lang.Thread.run(Thread.java:748) [na:1.8.0_161]
Caused by: com.netflix.client.ClientException: Load balancer does not have available server for client: microservice-provider-user
at com.netflix.loadbalancer.LoadBalancerContext.getServerFromLoadBalancer(LoadBalancerContext.java:483) ~[ribbon-loadbalancer-2.2.4.jar:2.2.4]
at com.netflix.loadbalancer.reactive.LoadBalancerCommand$1.call(LoadBalancerCommand.java:184) ~[ribbon-loadbalancer-2.2.4.jar:2.2.4]
at com.netflix.loadbalancer.reactive.LoadBalancerCommand$1.call(LoadBalancerCommand.java:180) ~[ribbon-loadbalancer-2.2.4.jar:2.2.4]
at rx.Observable.unsafeSubscribe(Observable.java:10256) [rxjava-1.3.6.jar:1.3.6]
at rx.internal.operators.OnSubscribeConcatMap.call(OnSubscribeConcatMap.java:94) ~[rxjava-1.3.6.jar:1.3.6]
at rx.internal.operators.OnSubscribeConcatMap.call(OnSubscribeConcatMap.java:42) ~[rxjava-1.3.6.jar:1.3.6]
at rx.Observable.unsafeSubscribe(Observable.java:10256) [rxjava-1.3.6.jar:1.3.6]
at rx.internal.operators.OperatorRetryWithPredicate$SourceSubscriber$1.call(OperatorRetryWithPredicate.java:127) ~[rxjava-1.3.6.jar:1.3.6]
at rx.internal.schedulers.TrampolineScheduler$InnerCurrentThreadScheduler.enqueue(TrampolineScheduler.java:73) ~[rxjava-1.3.6.jar:1.3.6]
at rx.internal.schedulers.TrampolineScheduler$InnerCurrentThreadScheduler.schedule(TrampolineScheduler.java:52) ~[rxjava-1.3.6.jar:1.3.6]
at rx.internal.operators.OperatorRetryWithPredicate$SourceSubscriber.onNext(OperatorRetryWithPredicate.java:79) ~[rxjava-1.3.6.jar:1.3.6]
at rx.internal.operators.OperatorRetryWithPredicate$SourceSubscriber.onNext(OperatorRetryWithPredicate.java:45) ~[rxjava-1.3.6.jar:1.3.6]
at rx.internal.util.ScalarSynchronousObservable$WeakSingleProducer.request(ScalarSynchronousObservable.java:276) ~[rxjava-1.3.6.jar:1.3.6]
at rx.Subscriber.setProducer(Subscriber.java:209) ~[rxjava-1.3.6.jar:1.3.6]
at rx.internal.util.ScalarSynchronousObservable$JustOnSubscribe.call(ScalarSynchronousObservable.java:138) ~[rxjava-1.3.6.jar:1.3.6]
at rx.internal.util.ScalarSynchronousObservable$JustOnSubscribe.call(ScalarSynchronousObservable.java:129) ~[rxjava-1.3.6.jar:1.3.6]
at rx.internal.operators.OnSubscribeLift.call(OnSubscribeLift.java:48) [rxjava-1.3.6.jar:1.3.6]
at rx.internal.operators.OnSubscribeLift.call(OnSubscribeLift.java:30) [rxjava-1.3.6.jar:1.3.6]
at rx.internal.operators.OnSubscribeLift.call(OnSubscribeLift.java:48) [rxjava-1.3.6.jar:1.3.6]
at rx.internal.operators.OnSubscribeLift.call(OnSubscribeLift.java:30) [rxjava-1.3.6.jar:1.3.6]
at rx.internal.operators.OnSubscribeLift.call(OnSubscribeLift.java:48) [rxjava-1.3.6.jar:1.3.6]
at rx.internal.operators.OnSubscribeLift.call(OnSubscribeLift.java:30) [rxjava-1.3.6.jar:1.3.6]
at rx.Observable.subscribe(Observable.java:10352) [rxjava-1.3.6.jar:1.3.6]
at rx.Observable.subscribe(Observable.java:10319) [rxjava-1.3.6.jar:1.3.6]
at rx.observables.BlockingObservable.blockForSingle(BlockingObservable.java:443) ~[rxjava-1.3.6.jar:1.3.6]
at rx.observables.BlockingObservable.single(BlockingObservable.java:340) ~[rxjava-1.3.6.jar:1.3.6]
at com.netflix.client.AbstractLoadBalancerAwareClient.executeWithLoadBalancer(AbstractLoadBalancerAwareClient.java:112) ~[ribbon-loadbalancer-2.2.4.jar:2.2.4]
at org.springframework.cloud.openfeign.ribbon.LoadBalancerFeignClient.execute(LoadBalancerFeignClient.java:63) ~[spring-cloud-openfeign-core-2.0.0.M1.jar:2.0.0.M1]
... 32 common frames omitted 2018-06-07 14:00:17.616 INFO 5188 --- [trap-executor-0] c.n.d.s.r.aws.ConfigClusterResolver : Resolving eureka endpoints via configuration

 4. 为Feign禁用Hystrix

  上面说过,在Spring Cloud中,只要Hystrix在项目的classpath中,Feign就会使用断路器包裹Feign客户端的所有方法。这样虽然方便,但是很多场景下并不需要该功能。

  全局禁用Hystrix,只须在 application.yml 中配置 feign.hystrix.enabled=false 即可

  借助Feign的自定义配置,可轻松为指定名称的Feign客户端禁用Hystrix。

  > 创建配置类

package com.itmuch.cloud.microserviceconsumermoviefeignhystrixfallbackfactory.config;

import feign.Feign;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Scope; @Configuration
public class FeignDisableHystrixConfiguration { @Bean
@Scope("prototype")
public Feign.Builder feignBuilder() {
return Feign.builder();
} }

  > 在想要禁用Hystrix的@FeignClient引用该配置类即可

@FeignClient(name = "microservice-provider-user", configuration = FeignDisableHystrixConfiguration.class)
public interface UserFeignClient { }

5. 总结

  本文讲了Feign使用Hystrix的各种知识。包括使用、检查回退原因、禁用Hystrix等。

  下文将讲解Hystrix的监控。敬请期待~~~

6. 参考

  周立 --- 《Spring Cloud与Docker微服务架构与实战》

SpringCloud系列十六:Feign使用Hystrix的更多相关文章

  1. SpringCloud系列十五:使用Hystrix实现容错

    1. 回顾 上文讲解了容错的重要性,以及容错需要实现的功能. 本文来讲解使用Hystrix实现容错. 2. Hystrix简介 Hystrix是Netflix开源的一个延迟和容错库,用于隔离访问远程系 ...

  2. S3C2416裸机开发系列十六_sd卡驱动实现

    S3C2416裸机开发系列十六 sd卡驱动实现 象棋小子    1048272975 SD卡(Secure Digital Memory Card)具有体积小.容量大.传输数据快.可插拔.安全性好等长 ...

  3. 跟我学SpringCloud | 第十六篇:微服务利剑之APM平台(二)Pinpoint

    目录 SpringCloud系列教程 | 第十六篇:微服务利剑之APM平台(二)Pinpoint 1. Pinpoint概述 2. Pinpoint主要特性 3. Pinpoint优势 4. Pinp ...

  4. 学习ASP.NET Core Razor 编程系列十六——排序

    学习ASP.NET Core Razor 编程系列目录 学习ASP.NET Core Razor 编程系列一 学习ASP.NET Core Razor 编程系列二——添加一个实体 学习ASP.NET ...

  5. 小D课堂 - 新版本微服务springcloud+Docker教程_5-04 feign结合hystrix断路器开发实战下

    笔记 4.Feign结合Hystrix断路器开发实战<下>     简介:讲解SpringCloud整合断路器的使用,用户服务异常情况     1.feign结合Hystrix       ...

  6. 小D课堂 - 新版本微服务springcloud+Docker教程_5-03 feign结合hystrix断路器开发实战上

    笔记 3.Feign结合Hystrix断路器开发实战<上>     简介:讲解SpringCloud整合断路器的使用,用户服务异常情况 1.加入依赖          注意:网上新旧版本问 ...

  7. 为什么不让用join?《死磕MySQL系列 十六》

    大家好,我是咔咔 不期速成,日拱一卒 在平时开发工作中join的使用频率是非常高的,很多SQL优化博文也让把子查询改为join从而提升性能,但部分公司的DBA又不让用,那么使用join到底有什么问题呢 ...

  8. SpringCloud系列十二:手动创建Feign

    1. 回顾 上文讲解了自定义Feign.但是在某些场景下,前文自定义Feign的方式满足不了需求,此时可使用Feign Builder API手动创建Feign. 本文围绕以下场景,为大家讲解如何手动 ...

  9. SpringCloud系列十:使用Feign实现声明式REST调用

    1. 回顾 前文的示例中是使用RestTemplate实现REST API调用的,代码大致如下: @GetMapping("/user/{id}") public User fin ...

随机推荐

  1. OpenVPN设置客户端固定IP

    在使用openvpn的过程中,多台客户端连接上同一台openvpn服务器之后,客户端的的IP地扯经常变动,导致客户端之间无法正常通讯,openvpn的版本变动也导致了固定IP地扯的配置不同,用以下方法 ...

  2. (转)探索C++的秘密之详解extern "C",这就是为什么很多.lib被我们正确调用确总是无法解析的。

    (转载,绝对的有用) lib被我们正确调用确总是无法解析.这是C++编译和C编译的区别 时常在cpp的代码之中看到这样的代码: #ifdef __cplusplus extern "C&qu ...

  3. Nand Flash与Nor

    转:http://www.360doc.com/content/11/1215/15/1299815_172458274.shtml Flash经常在一些地方被提到,一直没认真去理解它们的区别,因此, ...

  4. Microsoft office(2)多级标题的设置

    在Microsoft office中要达到下面的标题结构: 1.首先将文字准备好: 2.将“绪论”,“无线...介绍”等章节标题分别选中 :段落-->大纲级别-->1级 3.同样的,“研究 ...

  5. Spring与Quartz的整合

    Quartz Quartz是一个完全由Java编写的开源作业调度框架,为在Java应用程序中进行作业调度提供了简单却强大的机制.Quartz允许开发人员根据时间间隔来调度作业.它实现了作业和触发器的多 ...

  6. 深入理解Java中为什么内部类可以访问外部类的成员

    内部类简介 虽然Java是一门相对比较简单的编程语言,但是对于初学者, 还是有很多东西感觉云里雾里, 理解的不是很清晰.内部类就是一个经常让初学者感到迷惑的特性. 即使现在我自认为Java学的不错了, ...

  7. Linux VSFTP服务器详细配置

    Linux VSFTP服务器 1.开启服务 [root@localhost root]# service vsftpd start Starting vsftpd for vsftpd:        ...

  8. Spring框架学习(8)spring mvc上传下载

    内容源自:spring mvc上传下载 如下示例: 页面: web.xml: <?xml version="1.0" encoding="UTF-8"?& ...

  9. CentOS7 Failed to start LSB: Bring up/down networking. 已解决!!!

    服务器更换了主板之前配置的静态IP发现启动网卡出现异常. 执行 service network restart 出现以下错误 Restarting network (via systemctl):  ...

  10. Google Maps API v2密钥申请

    1. 进入到Google APIs Console页面 https://code.google.com/apis/console/ 点击左边导航栏的Seivices进入 在All services 的 ...