Feign声明式HTTP客户端

1. Feign的定义

Feign是Netflix开源的声明式客户端

解析:声明式HTTP客户端,我们只需要声明一个接口,Feign就会通过我们定义的接口,自动构造请求的目标地址,并完成发送请求
GitHub地址:https://github.com/openfeign/feign

2. 整合Feign

2.1 加依赖
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-openfeign</artifactId>
            <version>2.0.2.RELEASE</version>
        </dependency>
2.2 加注解

在启动类上面加@EnableFeignClients注解

3. 实际应用

首先我们之前服务之间的调用使用的是RestTemplate,使用RestTemplate会存在一些问题。所以我们考虑使用Feign代替RestTemplate,接下来我们就实现一下:
我们是内容中心调用用户中心的服务,所以我们在内容中心添加一个用户中心服务的接口类,代码如下:

package com.chuxin.contentcenter.feignclient;

import com.chuxin.contentcenter.dao.dto.UserDTO;
import feign.Param;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;

/**
 * @FileName: UserFeignClients
 * @Description: 用户中心的Feign远程调用接口类
 * @author: <a href="mailto: muyuanpei@camelotchina.com">myp</a>
 * @create: 2019-08-16 14:17
 * @Copyright: (c) 初心科技有限公司(待创)
 */
//name值为用户服务的名称
@FeignClient(name = "user-center")
public interface UserCenterFeignClient {

    @GetMapping("/users?id={id}")
    UserDTO findById(@PathVariable("id") Integer id);

}

然后我们在业务代码里面就可以通过该接口类直接调用就可以了。

@Autowired
private UserCenterFeignClient userCenterFeignClient;
//业务代码里这样直接调用就ok了
UserDTO userDTO = userCenterFeignClient.findById(userId);

通过使用FeignClient的方式相对于使用RestTemplate方式,可以解决以下问题:

  1. 编码的可读性差
  2. 复杂的url难以维护
  3. 难以响应需求的变化,变化很没有幸福感
  4. 编程体验不统一

4. Feign的组成

Feign的源码里面使用了大量的设计模式,比如建造者模式,代理模式等等。

image.png

1. Feign.Builder:Feign的入口,每一个FeignClient都是由他构建的
2. Client:指定Feign的底层用什么去请求。Feign.Client.Default使用的是用urlconnection去请求的,urlconnection没有连接池,也没有资源管理的概念,性能不是特别好;LoadBalancerFeignClient这个类用到了代理模式,代理了Client接口,这意味着你可以传一个你喜欢的Client过来使用,默认就是Client.Default
3.Contract:注解支持,Feign支持使用SpringMVC的注解,是由SpringMVCContract实现的

5. Feign的细粒度配置

和ribbon一样,两种方式。代码方式和属性方式
以配置Feign的日志打印级别入手学习(默认Feign是不打印任何日志的),spring打印日志级别是在配置文件中配置如下代码就可以了,但是Feign这样配置可不行

logging:
  level:
    com.chuxin: debug

Feign的四种自定义日志级别

级别 打印内容 适用场景
NONE(默认值) 不记录任何日志
BASIC 仅记录请求方式、url、响应状态码以及执行时间 生产环境
HEADERS 记录BASIC级别基础上,记录请求和响应的hearder
FULL 记录请求和响应的header、body和元数据(全部信息) 开发环境

5.1 代码方式

我们举例配置FULL级别的日志打印
首先我们在上面的基础上改一下UserCenterFeignClient.java这个类,在上面的注解添加configuration = xxx.class即可,修改后代码如下:

package com.chuxin.contentcenter.feignclient;

import com.chuxin.contentcenter.config.UserCenterFeignConfig;
import com.chuxin.contentcenter.dao.dto.UserDTO;
import feign.Param;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;

/**
 * @FileName: UserFeignClients
 * @Description: 用户中心的Feign远程调用接口类
 * @author: <a href="mailto: muyuanpei@camelotchina.com">myp</a>
 * @create: 2019-08-16 14:17
 * @Copyright: (c) 初心科技有限公司(待创)
 */
//name值为用户服务的名称
@FeignClient(name = "user-center" ,configuration = UserCenterFeignConfig.class)
public interface UserCenterFeignClient {

    @GetMapping("/users?id={id}")
    UserDTO findById(@PathVariable("id") Integer id);

}

UserCenterFeignConfig类如下:

package com.chuxin.contentcenter.config;

import feign.Logger;
import org.springframework.context.annotation.Bean;

/**
 * @FileName: UserCenterFeignConfig
 * @Description: 配置Feign日志打印级别的配置类。也可以添加其他的配置
 * @author: <a href="mailto: muyuanpei@camelotchina.com">myp</a>
 * @create: 2019-08-16 15:13
 * @Copyright: (c) 初心科技有限公司(待创)
 */
//@Configuration
public class UserCenterFeignConfig {

    @Bean
    public Logger.Level level(){
        //配置Feign打印所有请求的细节
        return Logger.Level.FULL;
    }
}
/**
 * 注意:
 * @Configuration这个注解如果加上就需要将这个类放到启动类扫描不到的包下面,如果不加,这个类就放在启动类可以扫描的包下面
 * 如果@Configuration注解使用错误,就会存在父子上下文重复问题
 * */

最后在配置文件中添加,如下配置:

# 配置日志打印级别
logging:
  level:
    # 接口全路径:debug级别日志
    com.chuxin.contentcenter.feifnclient.UserCenterFeignClient: debug

这样就配置完成了,在进行调用就会打印Feign的日志了。

5.2 属性方式

这个就简单多了,在文章上面第三点的基础上,在配置文件中添加一行配置就可以搞定了
配置代码如下:

feign:
  client:
    config:
      # 想要调用的微服务名称
      user-center:
        loggerLevel: full

这样就可以了,完成了和代码配置一样的效果

6. Feign的全局配置

6.1 代码方式

在启动类上面添加注解@EnableFeignClients(defaultConfiguration = UserCenterFeignConfig.class)
然后添加一个全局的配置类就ok了,配置类放在启动类可以扫描的包结构下,配置类代码如下:

package com.chuxin.contentcenter.config;

import feign.Logger;
import org.springframework.context.annotation.Bean;

/**
 * @FileName: UserCenterFeignConfig
 * @Description: 配置Feign日志打印级别的配置类。也可以添加其他的配置
 * @author: <a href="mailto: muyuanpei@camelotchina.com">myp</a>
 * @create: 2019-08-16 15:13
 * @Copyright: (c) 初心科技有限公司(待创)
 */
public class GlobalFeignConfig {

    @Bean
    public Logger.Level level(){
        //配置Feign打印所有请求的细节
        return Logger.Level.FULL;
    }

}
/**
 * 注意:
 * 这个注解如果加上就需要将这个类放到启动类扫描不到的包下面,如果不加,这个类就放在启动类可以扫描的包下面
 * 如果@Configuration注解使用错误,就会存在父子上下文重复问题
 * */

完成!!!

6.2 属性方式

在配置文件中,添加如下配置即可:

feign:
  client:
    config:
      # 将想要调用的微服务名称换成default就可以实现属性方式的全局配置了
      default:
        loggerLevel: full

7. Feign支持的配置项

使用代码方式和使用属性方式支持的配置项稍有不同

7.1 使用代码方式支持的配置项
配置项 作用
Logger.Level 指定日志级别
Retryer 指定重试策略
ErrorDecoder 指定错误解码器
Request.Options 超时时间
Collection<RequestInterceptor> 拦截器
SetterFactory 用于设置Hystrix的配置属性,Feign整合Hystrix才会用
7.2 使用属性方式支持的配置项
feign:
  client:
    config:
      # 想要调用的微服务名称
      default:
        loggerLevel: full # 日志级别四种: NONE(默认值)、BASIC、HEADERS、FULL
        connectTimeout: 5000 # 连接超时时间
        readTimeout: 5000 # 读取超时时间
        errorDecoder: com.example.SimpleErrorDecoder # 错误解码器
        retryer: com.example.SimpleRetryer # 重试策略
        requestInterceptor: com.example.SimpleRequestInterceptor # 拦截器
        # 是否对404错误码解码
        # 处理逻辑详情见feign.SynchronousMethodHandler#executeAndDecode
        decode404: false
        encoder: com.example.SimpleEncoder # 编码器
        decoder: com.example.SimpleDecoder # 解码器
        contract: com.example.SimpleContract # 契约

8. 对比

image.png

image.png

优先级由低到高:全局代码 < 全局属性 < 细粒度代码 < 细粒度属性

9. 配置的最佳实践

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

推荐阅读更多精彩内容