springcloud系列之openfeign

微信搜索【小二说码】关注,定期发布文章,欢迎关注讨论

Feign

我来说Feign

  • 本文的cloud的版本为:Greenwich.RELEASE
  • Feign(不就是大粪么!!_ 这个东西可不简单哦)是什么?根据官网解释:
    • 客户端组件,提供客户端和服务端之间调用。
    • 可以通过@Configuration注解或者配置文件来加载配置
    • 支持SpringMVC注解,并使用HttpMessageConverters作为消息转换器,比如@GetMapping
    • 两大重量级护法:Ribbon来实现负载和重试;Hystrix来实现降级和熔断
      Feign组件
  • FeignClient通过JDK动态代理来构建Client对象,并封装方法和参数到对象Map<Method, MethodHandler>,调用的时候通过方法名和参数来调用

服务远程调用方式

@Autowired
private LoadBalancerClient loadBalancerClient;
@Resource
private RestTemplate restTemplate;
// 调用 这里示例
restTemplate.getForObject(http:ip+port+path,xxx);
// 引入Bean
@LoadBalanced
@Bean
public RestTemplate restTemplate() {
    return new RestTemplate();
}
// 直接在类中注入
@Resource
private RestTemplate restTemplate;

// 引用
// 调用 这里示例
restTemplate.getForObject(serviceId+path,xxx);
  • 方式3:本章的大杀器Feign 通过集成Ribbon,代理集成功能实现接口方式的调用,@FeignClient("service-name")
// 直接在类中注入标注了@FeignClient注解的 orderService
@Autowired 
private OrderService orderService;
  • 前面两种方式调用都比较麻烦,需要注入对象并且在调用的时候需要拼接http,而第三种Feign的方式是直接通过注入对象的方式来处理,使用起来相当方便,像使用本地的Service,所以重点讲解

Feign开发

入门使用
高级使用
自定义配置(日志、拦截器、编码和解码)
  • 日志bean配置方式
    • 在FeignClient中增加configuration @FeignClient(name = "storage", fallback = StorageFallback.class, configuration = FeignConfiguration.class)
    • 覆盖默认配置的方式1:FeignConfiguration配置bean,重写默认的Feign配置,这个时候类不要配置@Configuration注解,避免覆盖了其它Feign的默认配置
// 千万不要配置@Configuration注解
@Slf4j
public class FeignConfiguration {
    // 配置Bean
    @Bean
    public Logger.Level level() {
        return Logger.Level.FULL;
    }
}

// 注意如果日志不生效需要配置指定client的日志级别到debug
logging:
  level:
    com.feign.XXXClient: debug
  • 覆盖默认配置的方式2:配置文件(yml)配置方式
feign:
  client:
    config:
      default:
        loggerLevel: full
        requestInterceptors:
          # 可以用来传递token,跟踪id等需要通过header传递的信息
          - com.frank.interceptor.StorageFeignInterceptor
  • 如果Bean配置方式和配置文件同时存在,配置文件的方式会优先
  • 拦截器、编码和解码的配置也同样支持上面两种方式
眼花缭乱的时间配置
  • 先来个求极限的算法吧!!相信很多:好汉都被难倒了,那么最大值怎么算出来的呢?咚咚咚。。。不卖关子了。最大时间=(ReadTimeout?+ConnectTimeout) * (MaxAutoRetries + 1) * (MaxAutoRetriesNextServer + 1)(?表示0次或者1次),是不是比数据的极限算法简单很多呢!高数各种极限求法眼花缭乱,早就还给老师了,哈哈!注意:ribbon默认的情况下是单台机器重试次数一次,重试一台机器
# ribbon超时时间 
# 每台机器最大重试次数,默认是一次,就是说如果没有配置情况下请求超时会重试一次
storage.ribbon.MaxAutoRetries=2
# 再重试几台机器
storage.ribbon.MaxAutoRetriesNextServer=2
# 连接超时,连接超时可设置较小
storage.ribbon.ConnectTimeout=1000
# 业务处理超时
storage.ribbon.ReadTimeout=2000
# 在所有HTTP Method进行重试,默认配置是false,生产环境如果配置
# 为true需要设置幂等
storage.ribbon.OkToRetryOnAllOperations=true
  • 上述配置的优先级别低于fegin.client.config.default.xxxTimeout的时间配置,这个配置会覆盖ribbon的时间配置,上面ribbon配置的时间和重试参数统统不生效
feign:
  client:
    config:
      # 指定自己的feign的名字,默认default对所有的feign生效
      default:
        connectTimeout: 5000
        readTimeout: 5000
  • 配置超时时间合理的情况下,建议hystix=connectTimeout+readTimeout,生效时间优先级 feign > hystrix > ribbon > http
降级&熔断
  • 降级的配置需要在client来实现
  • 开启配置
feign:
  hystrix:
    enabled: true
hystrix:
  command:
    # 这里是全局配置,可以针对每个commandKey来配置,也可以通过类#方法
    # 获取类#方法(args)的快捷方式:Feign.configKey(target.type(), method)
    default:
      execution:
        isolation:
          thread:
            timeoutInMilliseconds: 3000
  • 降级配置:在@FeignClient增加fallBack配置,fallBack配置类实现client并加入到spring上下文中去,当然也可以实现factory接口
@FeignClient(name = "storage", fallback = StorageClientFallback.class)
protected interface StorageClient{
    @GettMapping("/fallback")
    String fallback(Integer flag);
}

// 内部类的不用添加Bean上下文注解,如果单独实现需要配置@Component注解
static class StorageClientFallback implements StorageClient{
    @Override
    public String fallback(Integer flag) {
        return "fallback";
    }
}
  • 如果在默认的5秒钟内出现20次错误的情况下,断路器会打开,所有请求直接熔断
  • hystrix command 配置command

源码阅读

Feign源码之@EnableFeignClients
  • 加载在启动类的配置给人的第一直觉就是初始化组件用的,没错这里的@EnableFeignClients的功能就是加载Feign的定义,具体定义了什么内容呢?
    • FeignClientsRegistrar类实现了ImportBeanDefinitionRegistrar接口,在方法中注册了Feign的配置以及FeignClient的定义
    • 画外音:很多组件都是通过这种方式来加载的,所以平常在组件开发的过程中也可以通过实现ImportBeanDefinitionRegistrar接口来实现自定义组件的加载
Feign源码之FeignClientFactoryBean
  • 看到XXXFactoryBean对象(画外音:创建spring对象的方式之一,可以想象对象创建的其它方式),可以猜测是通过工厂Bean的方式来创建对象。在Spring上下文初始化的时候,需要加载Client的时候,通过FactoryBean来创建Client对象的

  • 大致流程


    Client主要流程
  • 核心创建方法如下:

public <T> T newInstance(Target<T> target) {
    Map<String, MethodHandler> nameToHandler = targetToHandlersByName.apply(target);
    // 方法和方法处理Handler的映射关系
    Map<Method, MethodHandler> methodToHandler = new LinkedHashMap<Method, MethodHandler>();
    List<DefaultMethodHandler> defaultMethodHandlers = new LinkedList<DefaultMethodHandler>();

    for (Method method : target.type().getMethods()) {
      if (method.getDeclaringClass() == Object.class) {
        continue;
      } else if (Util.isDefault(method)) {
        DefaultMethodHandler handler = new DefaultMethodHandler(method);
        defaultMethodHandlers.add(handler);
        methodToHandler.put(method, handler);
      } else {
        methodToHandler.put(method, nameToHandler.get(Feign.configKey(target.type(), method)));
      }
    }
    // 创建InvocationHandler
    InvocationHandler handler = factory.create(target, methodToHandler);
    // 创建动态代理对象
    T proxy = (T) Proxy.newProxyInstance(target.type().getClassLoader(),
        new Class<?>[] {target.type()}, handler);

    for (DefaultMethodHandler defaultMethodHandler : defaultMethodHandlers) {
      defaultMethodHandler.bindTo(proxy);
    }
    return proxy;
  }

你们的点赞和关注是我创作的最大动力,有什么不足和错误的地方欢迎留言,微信搜索关注小二说码

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,324评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,303评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,192评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,555评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,569评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,566评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,927评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,583评论 0 257
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,827评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,590评论 2 320
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,669评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,365评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,941评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,928评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,159评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,880评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,399评论 2 342

推荐阅读更多精彩内容