如何使用原生的Feign

什么是Feign

Feign 是由 Netflix 团队开发的一款基于 Java 实现的 HTTP client,借鉴了 Retrofit、 JAXRS-2.0、WebSocket 等类库。通过 Feign,我们可以像调用方法一样非常简单地访问 HTTP API。这篇博客将介绍如何使用原生的 Feign,注意,是原生的,不是经过 Spring 层层封装的 Feign。

补充一下,在 maven 仓库中搜索 feign,我们会看到两种 Feign: OpenFeign Feign 和 Netflix Feign。它们有什么区别呢?简单地说,OpenFeign Feign 的前身就是 Netflix Feign,因为 Netflix Feign 从 2016 年开始就不维护了,所以建议还是使用 OpenFeign Feign。

如何使用原生的Feign

为什么使用Feign

为什么要使用HTTP client

首先,因为 Feign 本身是一款 HTTP client,所以,这里先回答:为什么使用 HTTP client?

假设不用 HTTP client,我们访问 HTTP API 的过程大致如下。是不是相当复杂呢?直接操作 socket 已经非常麻烦了,我们还必须在熟知 HTTP 协议的前提下自行完成报文的组装和解析,代码的复杂程度可想而知。

如何使用原生的Feign

那么,这个过程是不是可以更简单一些呢?

我们可以发现,在上面的图中,红框的部分是相对通用的,是不是可以把这些逻辑封装起来?基于这样的思考,于是就有了 HTTP client(根据类库的不同,封装的层次会有差异)。

所以,为什么要使用 HTTP client 呢?简单地说,就是为了让我们更方便地访问 HTTP API。

为什么要使用Feign

HTTP client 的类库还有很多,例如 Retrofit、JDK 自带的 HttpURLConnection、Apache HttpClient、OkHttp、Spring 的 RestTemplate,等等。我很少推荐说要使用哪种具体的类库,如果真的要推荐 Feign 的话,主要是由于它优秀的扩展性(不是一般的优秀,后面的使用例子就可以看到)。

如何使用Feign

关于如何使用 Feign,官方给出了非常详细的文档,在我看过的第三方类库中,算是比较少见的。

本文用到的例子也是参考了官方文档。

项目环境说明

os:win 10

jdk:1.8.0_231

maven:3.6.3

IDE:Spring Tool Suite 4.6.1.RELEASE

引入依赖

这里引入 gson,是因为入门例子需要有一个 json 解码器。


        11.2

            io.github.openfeign
            feign-core
            ${feign.version}

            io.github.openfeign
            feign-gson
            ${feign.version}

入门例子

入门例子中使用 Feign 来访问 github 的接口获取 Feign 这个仓库的所有贡献者。

通过下面的代码可以发现, Feign 本质上是使用了动态代理来生成访问 HTTP API 的代码,定义 HTTP API 的过程有点像在定义 advice。

// 定义HTTP API
interface GitHub {

    @RequestLine("GET /repos/{owner}/{repo}/contributors")
    // @RequestLine(value = "GET /repos/{owner}/{repo}/contributors", decodeSlash = false)// 测试转义"/"、"+"
    // @RequestLine("GET /repos/{owner:[a-zA-Z]*}/{repo}/contributors")// 测试正则校验
    // @Headers("Accept: application/json") // 测试添加header
    List contributors(@Param("owner") String owner, @Param("repo") String repo);
}

public static class Contributor {
    String login;
    int contributions;
}

public class MyApp {

    public static void main(String... args) {
        // 获取用来访问HTTP API的代理类
        GitHub github = Feign.builder()
                .decoder(new GsonDecoder()) // 返回内容为json格式,所以需要用到json解码器
                // .options(new Request.Options(10, TimeUnit.SECONDS, 60, TimeUnit.SECONDS, true)) // 配置超时参数等
                .target(GitHub.class, "https://api.github.com");

        // 像调用方法一样访问HTTP API
        github.contributors("OpenFeign", "feign").stream()
            .map(contributor -> contributor.login + " (" + contributor.contributions + ")")
            .forEach(System.out::println);
    }
}

个性化配置

除了简单方便之外,Feign 还有一个很大的亮点,就是 有相当优秀的扩展性,几乎什么都可以自定义。下面是官方给的一张图,基本涵盖了 Feign 可以扩展的内容。每个扩展支持都有一个对应的适配包,例如,更换解码器为 jackson 时,需要引入 io.github.openfeign:feign-jackson的适配包。

如何使用原生的Feign

更换为Spring的注解

在入门例子中,我们使用 Feign 自带的注解来定义 HTTP API。但是,对于习惯了 Spring 注解的许多人来说,无疑需要增加学习成本。我们自然会问,Feign 能不能支持 Spring 注解呢?答案是肯定的。Feign 不但能支持 Spring 注解,还可以支持 JAX-RS、SOAP 等等。

如何使用原生的Feign

下面就是使用 Sping 注解定义 HTTP API 的例子。注意, pom 文件中要引入 io.github.openfeign:feign-spring4 的依赖

// 定义HTTP API
interface GitHub {

    @GetMapping("/repos/{owner}/{repo}/contributors")
    List contributors(@RequestParam("owner") String owner, @RequestParam("repo") String repo);
}

public class MyApp {

    public static void main(String... args) {
        // 获取用来访问HTTP API的代理类
        GitHub github = Feign.builder()
                .decoder(new GsonDecoder())
                .contract(new SpringContract())// 自定义contract
                .target(GitHub.class, "https://api.github.com");
    }
}

自定义解码器和编码器

在入门例子中,我们使用 gson 来解析 json。那么,如果我想把它换成 jackson 行不行?Feign 照样提供了支持。

如何使用原生的Feign

注意, pom 文件中要引入 io.github.openfeign:feign-jackson 的依赖

public class MyApp {

    public static void main(String... args) {
        // 获取用来访问HTTP API的代理类
        GitHub github = Feign.builder()
                .decoder(new JacksonDecoder()) // 自定义解码器
                .encoder(new JacksonEncoder()) // 自定义编码器
                .target(GitHub.class, "https://api.github.com");
    }
}

自定义内置的HTTP client

接下来的这个自定义就更厉害了。Feign 本身作为一款 HTTP client,竟然还可以支持其他 HTTP client。

如何使用原生的Feign

这里用 OkHttp 作例子。注意, pom 文件中要引入 io.github.openfeign:feign-okhttp 的依赖

public class MyApp {

    public static void main(String... args) {
        // 获取用来访问HTTP API的代理类
        GitHub github = Feign.builder()
                .decoder(new GsonDecoder())
                .client(new OkHttpClient())// 自定义client
                .target(GitHub.class, "https://api.github.com");
    }
}

自定义拦截器

我们访问外部接口时,有时需要带上一些特定的 header,例如,应用标识、token,我们可以通过两种方式实现:一是使用注解定义 HTTP API,二是使用拦截器(更常用)。下面的例子中,使用拦截器给请求添加 token 请求头。

public class MyInterceptor implements RequestInterceptor {

    @Override
    public void apply(RequestTemplate template) {
        template.header("token", LoginUtils.getCurrentToken());
    }
}
public class MyApp {

    public static void main(String... args) {
        // 获取用来访问HTTP API的代理类
        GitHub github = Feign.builder()
                .decoder(new GsonDecoder())
                .requestInterceptor(new MyInterceptor())
                .target(GitHub.class, "https://api.github.com");
    }
}

自定义重试器

默认情况下,Feign 访问 HTTP API 时,如果抛出 IOException,它会认为是短暂的网络异常而发起重试,这时,Feign 会使用默认的重试器 feign.Retryer.Default(最多重试 5 次),如果不想启用重试,则可以选择另一个重试器 feign.Retryer.NEVER_RETRY。当然,我们也可以自定义。

奇怪的是,Feign 通过重试器的 continueOrPropagate(RetryableException e)方法是否抛出 RetryableException来判断是否执行重试,为什么不使用 true 或 false 来判断呢?

注意,重试器是用来判断是否执行重试,自身不包含重试的逻辑。

public class MyRetryer implements Retryer {

    int attempt = 0;

    @Override
    public void continueOrPropagate(RetryableException e) {
        // 如果把RetryableException抛出,则不会继续重试
        // 否则继续重试
        if(attempt++ >= 3) {// 重试三次
            throw e;
        }
    }

    @Override
    public Retryer clone() {
        return this;
    }
}
public class MyApp {

    public static void main(String... args) {
        // 获取用来访问HTTP API的代理类
        GitHub github = Feign.builder()
                .decoder(new GsonDecoder())
                .retryer(new MyRetryer())
                //.retryer(Retryer.NEVER_RETRY) // 不重试
                .exceptionPropagationPolicy(ExceptionPropagationPolicy.UNWRAP)
                .target(GitHub.class, "https://api.github.com");
    }
}

结语

以上,基本讲完 Feign 的使用方法,其实 Feign 还有其他可以扩展的东西,例如,断路器、监控等等。感兴趣的话,可以自行分析。

最后,感谢阅读。

参考资料

Feign github

相关源码请移步:https://github.com/ZhangZiSheng001/feign-demo

本文为原创文章,转载请附上原文出处链接:https://www.cnblogs.com/ZhangZiSheng001/p/14989165.html

Original: https://www.cnblogs.com/ZhangZiSheng001/p/14989165.html
Author: 子月生
Title: 如何使用原生的Feign

原创文章受到原创版权保护。转载请注明出处:https://www.johngo689.com/575784/

转载文章受原作者版权保护。转载请注明原作者出处!

(0)

大家都在看

  • 【StoneDB故障诊断】数据库实例crash

    系统负载高 系统负载高导致了申请系统资源失败,最后数据库实例crash,常见原因及诊断方法详见系统资源瓶颈诊断。 数据页损坏 如果是硬件故障或者磁盘空间满了,向数据文件写入时,很容…

    数据库 2023年5月24日
    0131
  • java读写锁

    工作遇到了金钱计算,需要用到读写锁保证数据安全。记录一下。 单纯读没有限制,读写、写写的时候会有安全问题。 _hashMap_存在并发线程安全问题,而 _hashtable_线程安…

    数据库 2023年6月16日
    090
  • 21粤比武

    先进行密码绕过,在这个界面迅速按下方向键,然后按下e进入编辑模式 找到linux16这一行,将lang编码后面的全部删掉,加上 <span class=”ne-text”&g…

    数据库 2023年6月11日
    0106
  • eclipse反编译插件

    1、在eclipse的help—》Install New Software…中添加新软件开发,添加它的源: undefined name : jd – ec…

    数据库 2023年6月11日
    087
  • 正则表达式

    正则表达式:REGEXP,REGular EXPression。正则表达式分为两类: Basic REGEXP(基本正则表达式 Extended REGEXP(扩展正则表达式) 元…

    数据库 2023年6月15日
    0145
  • Mybatis基础知识大全!!!

    1. 简介 1.1什么是Mybatis 1.2 如何获得Mybatis 1.3 使用Mybatis的好处: 2.初涉Mybatis 2.1环境搭建 2.2、创建一个模块(项目) 2…

    数据库 2023年6月16日
    0123
  • chrome架构发展与提供的性能分析工具

    谷歌早期多进程架构分为插件进程(Plugin Process)、渲染进程(Render Process)、浏览器主进程(Browser Process) 插件进程负责插件的运行,通…

    数据库 2023年6月6日
    0332
  • MySQL 笔记

    情景一数据库概述基本术语DB : 数据库 ( Database )它是根据数据结构组织、存储和管理数据的仓库。它被视为电子档案柜,用户可以对文件中的数据进行添加、删除、修改、查找等…

    数据库 2023年5月24日
    096
  • 能尽量用数据库代替内存就用吧,减少整天担心内存问题

    游戏不好搞啊,设计的东西,能尽量简单就简单,代码太多判断就写死行了,反正它运行起来是对的就行了。 情形:09:00 昨天发生了很痛苦的一件事情,那就是游戏中data内存同步不到da…

    数据库 2023年6月14日
    078
  • MySQL45讲之随机查询和临时表

    本文介绍 MySQL 随机查询的工作流程、优化随机查询的方式、和临时表。 工作流程 根据下表结构建立 words 表,并通过过程插入 10000 条模拟数据。 CREATE TAB…

    数据库 2023年5月24日
    093
  • Oracle培训-介绍与体系架构

    1979年,公司推出Oracle 2,这是计算机软件史上第一个由纯软件公司开发的商用关系型数据库管理系统。公司改名为”关系软件公司” (Relational…

    数据库 2023年6月11日
    0115
  • mysql 函数、事件( 建立一个存储引擎为memory(已建好)的表,通过事件实现插入的每条数据30分钟后自动删除)

    use db; create table lg( id int unsigned, naem varchar(20), t timestamp, message varchar(1…

    数据库 2023年5月24日
    0121
  • 链表(Java)实现

    链表 先给出自定义的list接口,后面几种链表的实现了该接口 public interface List { //统计顺序表元素个数 int size(); //判断顺序表是否为空…

    数据库 2023年6月16日
    092
  • RadonDB MySQL Kubernetes 2.2.0 发布!

    摘要 RadonDB MySQL Kubernetes v2.2.0 于近日发布!该版本开始支持 MySQL 8.0,备份功能优化,并全面提升高可用稳定性。社区同步发起&#8221…

    数据库 2023年5月24日
    0118
  • logstash写入文件慢的问题排查记录

    终于找到根本原因了!!!!! logstash部署到k8s集群内部的,当所在节点的CPU资源被其他应用抢占时,logstash的处理速度就会降低 问题现象 logstash从kaf…

    数据库 2023年6月9日
    096
  • openpyxl使用总结

    设置表头单元格的颜色 fill = PatternFill("solid", fgColor=’FF000000′) font = Font(color=’00…

    数据库 2023年6月9日
    091
亲爱的 Coder【最近整理,可免费获取】👉 最新必读书单  | 👏 面试题下载  | 🌎 免费的AI知识星球