Feign api調用方式

Feign使用簡介

基本用法

基本的使用如下所示,一個對于canonical Retrofit sample的適配。

interface GitHub {// RequestLine注解聲明請求方法和請求地址,可以允許有查詢參數@RequestLine("GET /repos/{owner}/{repo}/contributors")List<Contributor> contributors(@Param("owner") String owner, @Param("repo") String repo);
}static class Contributor {String login;int contributions;
}public static void main(String... args) {GitHub github = Feign.builder().decoder(new GsonDecoder()).target(GitHub.class, "https://api.github.com");// Fetch and print a list of the contributors to this library.List<Contributor> contributors = github.contributors("OpenFeign", "feign");for (Contributor contributor : contributors) {System.out.println(contributor.login + " (" + contributor.contributions + ")");}
}

?


自定義

Feign?有許多可以自定義的方面。舉個簡單的例子,你可以使用?Feign.builder()?來構造一個擁有你自己組件的API接口。如下:

interface Bank {@RequestLine("POST /account/{id}")Account getAccountInfo(@Param("id") String id);
}
...
// AccountDecoder() 是自己實現的一個Decoder
Bank bank = Feign.builder().decoder(new AccountDecoder()).target(Bank.class, "https://api.examplebank.com");

?


多種接口

Feign可以提供多種API接口,這些接口都被定義為?Target<T>?(默認的實現是?HardCodedTarget<T>), 它允許在執行請求前動態發現和裝飾該請求。?
舉個例子,下面的這個模式允許使用當前url和身份驗證token來裝飾每個發往身份驗證中心服務的請求。

CloudDNS cloudDNS = Feign.builder().target(new CloudIdentityTarget<CloudDNS>(user, apiKey));

?


示例

Feign?包含了?GitHub?和?Wikipedia?客戶端的實現樣例.相似的項目也同樣在實踐中運用了Feign。尤其是它的示例后臺程序。


Feign集成模塊

Feign?可以和其他的開源工具集成工作。你可以將這些開源工具集成到?Feign?中來。目前已經有的一些模塊如下:

Gson

Gson?包含了一個編碼器和一個解碼器,這個可以被用于JSON格式的API。?
添加?GsonEncoder?以及?GsonDecoder?到你的?Feign.Builder?中, 如下:

GsonCodec codec = new GsonCodec();
GitHub github = Feign.builder().encoder(new GsonEncoder()).decoder(new GsonDecoder()).target(GitHub.class, "https://api.github.com");

?

Maven依賴:

<!-- https://mvnrepository.com/artifact/com.netflix.feign/feign-gson -->
<dependency><groupId>com.netflix.feign</groupId><artifactId>feign-gson</artifactId><version>8.18.0</version>
</dependency>

?

Jackson

Jackson?包含了一個編碼器和一個解碼器,這個可以被用于JSON格式的API。?
添加?JacksonEncoder?以及?JacksonDecoder?到你的?Feign.Builder?中, 如下:

GitHub github = Feign.builder().encoder(new JacksonEncoder()).decoder(new JacksonDecoder()).target(GitHub.class, "https://api.github.com");

?

Maven依賴:

  <!-- https://mvnrepository.com/artifact/com.netflix.feign/feign-gson --><dependency><groupId>com.netflix.feign</groupId><artifactId>feign-jackson</artifactId><version>8.18.0</version></dependency>

?

Sax

SaxDecoder?用于解析XML,并兼容普通JVM和Android。下面是一個配置sax來解析響應的例子:

api = Feign.builder().decoder(SAXDecoder.builder().registerContentHandler(UserIdHandler.class).build()).target(Api.class, "https://apihost");

?

Maven依賴:

<dependency><groupId>com.netflix.feign</groupId><artifactId>feign-sax</artifactId><version>8.18.0</version>
</dependency>

?

JAXB

JAXB?包含了一個編碼器和一個解碼器,這個可以被用于XML格式的API。?
添加?JAXBEncoder?以及?JAXBDecoder?到你的?Feign.Builder?中, 如下:

api = Feign.builder().encoder(new JAXBEncoder()).decoder(new JAXBDecoder()).target(Api.class, "https://apihost");

?

Maven依賴:

<!-- https://mvnrepository.com/artifact/com.netflix.feign/feign-gson -->
<dependency><groupId>com.netflix.feign</groupId><artifactId>feign-jaxb</artifactId><version>8.18.0</version>
</dependency>

JAX-RS

JAXRSContract?使用 JAX-RS 規范重寫覆蓋了默認的注解處理。下面是一個使用 JAX-RS 的例子:

interface GitHub {@GET @Path("/repos/{owner}/{repo}/contributors")List<Contributor> contributors(@PathParam("owner") String owner, @PathParam("repo") String repo);
}
// contract 方法配置注解處理器,注解處理器定義了哪些注解和值是可以作用于接口的
GitHub github = Feign.builder().contract(new JAXRSContract()).target(GitHub.class, "https://api.github.com");

?

Maven依賴:

<!-- https://mvnrepository.com/artifact/com.netflix.feign/feign-gson -->
<dependency><groupId>com.netflix.feign</groupId><artifactId>feign-jaxrs</artifactId><version>8.18.0</version>
</dependency>

?

OkHttp

OkHttpClient?使用?OkHttp?來發送?Feign?的請求,OkHttp?支持?SPDY?(SPDY是Google開發的基于TCP的傳輸層協議,用以最小化網絡延遲,提升網絡速度,優化用戶的網絡使用體驗),并有更好的控制http請求。?
要讓?Feign?使用?OkHttp?,你需要將?OkHttp?加入到你的環境變量中區,然后配置?Feign?使用?OkHttpClient,如下:

GitHub github = Feign.builder().client(new OkHttpClient()).target(GitHub.class, "https://api.github.com");

?

Maven依賴:

<!-- https://mvnrepository.com/artifact/com.netflix.feign/feign-gson -->
<dependency><groupId>com.netflix.feign</groupId><artifactId>feign-okhttp</artifactId><version>8.18.0</version>
</dependency>

?

Ribbon

RibbonClient?重寫了?Feign?客戶端的對URL的處理,其添加了 智能路由以及一些其他由Ribbon提供的彈性功能。?
集成Ribbon需要你將ribbon的客戶端名稱當做url的host部分來傳遞,如下:

// myAppProd是你的ribbon client name
MyService api = Feign.builder().client(RibbonClient.create()).target(MyService.class, "https://myAppProd");

?

Maven依賴:

<!-- https://mvnrepository.com/artifact/com.netflix.feign/feign-gson -->
<dependency><groupId>com.netflix.feign</groupId><artifactId>feign-ribbon</artifactId><version>8.18.0</version>
</dependency>

?

Hystrix

HystrixFeign?配置了?Hystrix?提供的熔斷機制。?
要在?Feign?中使用?Hystrix?,你需要添加Hystrix模塊到你的環境變量,然后使用?HystrixFeign?來構造你的API:

MyService api = HystrixFeign.builder().target(MyService.class, "https://myAppProd");

?

Maven依賴:

<!-- https://mvnrepository.com/artifact/com.netflix.feign/feign-gson -->
<dependency><groupId>com.netflix.feign</groupId><artifactId>feign-hystrix</artifactId><version>8.18.0</version>
</dependency>

?

SLF4J

SLF4JModule?允許你使用?SLF4J?作為?Feign?的日志記錄模塊,這樣你就可以輕松的使用?Logback,?Log4J?, 等 來記錄你的日志.?
要在?Feign?中使用?SLF4J?,你需要添加SLF4J模塊和對應的日志記錄實現模塊(比如Log4J)到你的環境變量,然后配置?Feign使用Slf4jLogger?:

GitHub github = Feign.builder().logger(new Slf4jLogger()).target(GitHub.class, "https://api.github.com");

?

Maven依賴:

<!-- https://mvnrepository.com/artifact/com.netflix.feign/feign-gson -->
<dependency><groupId>com.netflix.feign</groupId><artifactId>feign-slf4j</artifactId><version>8.18.0</version>
</dependency>

?


Feign 組成

Decoders

Feign.builder()?允許你自定義一些額外的配置,比如說如何解碼一個響應。假如有接口方法返回的消息不是?Response,?String,?byte[]?或者?void?類型的,那么你需要配置一個非默認的解碼器。?
下面是一個配置使用JSON解碼器(使用的是feign-gson擴展)的例子:

GitHub github = Feign.builder().decoder(new GsonDecoder()).target(GitHub.class, "https://api.github.com");

?

假如你想在將響應傳遞給解碼器處理前做一些額外的處理,那么你可以使用mapAndDecode方法。一個用例就是使用jsonp服務的時候:

// 貌似1.8.0版本中沒有mapAndDecode這個方法。。。
JsonpApi jsonpApi = Feign.builder().mapAndDecode((response, type) -> jsopUnwrap(response, type), new GsonDecoder()).target(JsonpApi.class, "https://some-jsonp-api.com");

?

Encoders

發送一個Post請求最簡單的方法就是傳遞一個?String?或者?byte[]?類型的參數了。你也許還需添加一個Content-Type請求頭,如下:

interface LoginClient {@RequestLine("POST /")@Headers("Content-Type: application/json")void login(String content);
}
...
client.login("{\"user_name\": \"denominator\", \"password\": \"secret\"}");

?

通過配置一個解碼器,你可以發送一個安全類型的請求體,如下是一個使用 feign-gson 擴展的例子:

static class Credentials {final String user_name;final String password;Credentials(String user_name, String password) {this.user_name = user_name;this.password = password;}
}interface LoginClient {@RequestLine("POST /")void login(Credentials creds);
}
...
LoginClient client = Feign.builder().encoder(new GsonEncoder()).target(LoginClient.class, "https://foo.com");client.login(new Credentials("denominator", "secret"));

?

@Body templates

@Body注解申明一個請求體模板,模板中可以帶有參數,與方法中?@Param?注解申明的參數相匹配,使用方法如下

interface LoginClient {@RequestLine("POST /")@Headers("Content-Type: application/xml")@Body("<login \"user_name\"=\"{user_name}\" \"password\"=\"{password}\"/>")void xml(@Param("user_name") String user, @Param("password") String password);@RequestLine("POST /")@Headers("Content-Type: application/json")// json curly braces must be escaped!// 這里JSON格式需要的花括號居然需要轉碼,有點蛋疼了。@Body("%7B\"user_name\": \"{user_name}\", \"password\": \"{password}\"%7D")void json(@Param("user_name") String user, @Param("password") String password);
}
...
// <login "user_name"="denominator" "password"="secret"/>
client.xml("denominator", "secret"); 
// {"user_name": "denominator", "password": "secret"}
client.json("denominator", "secret"); 

?

Headers

Feign?支持給請求的api設置或者請求的客戶端設置請求頭

給API設置請求頭

  • 使用?@Headers?設置靜態請求頭
// 給BaseApi中的所有方法設置Accept請求頭
@Headers("Accept: application/json")
interface BaseApi<V> {// 單獨給put方法設置Content-Type請求頭@Headers("Content-Type: application/json") @RequestLine("PUT /api/{key}") void put(@Param("key") String, V value); }
  • 設置動態值的請求頭
@RequestLine("POST /")
@Headers("X-Ping: {token}")
void post(@Param("token") String token);
  • 設置key和value都是動態的請求頭?
    有些API需要根據調用時動態確定使用不同的請求頭(e.g. custom metadata header fields such as “x-amz-meta-” or “x-goog-meta-“),?
    這時候可以使用?@HeaderMap?注解,如下:
// @HeaderMap 注解設置的請求頭優先于其他方式設置的
@RequestLine("POST /")
void post(@HeaderMap Map<String, Object> headerMap);

給Target設置請求頭

有時我們需要在一個API實現中根據不同的endpoint來傳入不同的Header,這個時候我們可以使用自定義的RequestInterceptor 或 Target來實現.?
通過自定義的 RequestInterceptor 來實現請查看?Request Interceptors?章節.?
下面是一個通過自定義Target來實現給每個Target設置安全校驗信息Header的例子:

  static class DynamicAuthTokenTarget<T> implements Target<T> {public DynamicAuthTokenTarget(Class<T> clazz,UrlAndTokenProvider provider,ThreadLocal<String> requestIdProvider);...@Overridepublic Request apply(RequestTemplate input) { TokenIdAndPublicURL urlAndToken = provider.get(); if (input.url().indexOf("http") != 0) { input.insert(0, urlAndToken.publicURL); } input.header("X-Auth-Token", urlAndToken.tokenId); input.header("X-Request-ID", requestIdProvider.get()); return input.request(); } } ... Bank bank = Feign.builder() .target(new DynamicAuthTokenTarget(Bank.class, provider, requestIdProvider));

這種方法的實現依賴于給Feign?客戶端設置的自定義的RequestInterceptor 或 Target。可以被用來給一個客戶端的所有api請求設置請求頭。比如說可是被用來在header中設置身份校驗信息。這些方法是在線程執行api請求的時候才會執行,所以是允許在運行時根據上下文來動態設置header的。?
比如說可以根據線程本地存儲(thread-local storage)來為不同的線程設置不同的請求頭。


高級用法

Base APIS

有些請求中的一些方法是通用的,但是可能會有不同的參數類型或者返回類型,這個時候可以這么用:

// 通用API
interface BaseAPI {@RequestLine("GET /health")String health();@RequestLine("GET /all") List<Entity> all(); } // 繼承通用API interface CustomAPI extends BaseAPI { @RequestLine("GET /custom") String custom(); } // 各種類型有相同的表現形式,定義一個統一的API @Headers("Accept: application/json") interface BaseApi<V> { @RequestLine("GET /api/{key}") V get(@Param("key") String key); @RequestLine("GET /api") List<V> list(); @Headers("Content-Type: application/json") @RequestLine("PUT /api/{key}") void put(@Param("key") String key, V value); } // 根據不同的類型來繼承 interface FooApi extends BaseApi<Foo> { } interface BarApi extends BaseApi<Bar> { }

Logging

你可以通過設置一個?Logger?來記錄http消息,如下:

GitHub github = Feign.builder().decoder(new GsonDecoder()).logger(new Logger.JavaLogger().appendToFile("logs/http.log")).logLevel(Logger.Level.FULL).target(GitHub.class, "https://api.github.com");

也可以參考上面的?SLF4J?章節的說明

Request Interceptors

當你希望修改所有的的請求的時候,你可以使用Request Interceptors。比如說,你作為一個中介,你可能需要為每個請求設置?X-Forwarded-For

static class ForwardedForInterceptor implements RequestInterceptor {@Override public void apply(RequestTemplate template) { template.header("X-Forwarded-For", "origin.host.com"); } } ... Bank bank = Feign.builder() .decoder(accountDecoder) .requestInterceptor(new ForwardedForInterceptor()) .target(Bank.class, "https://api.examplebank.com");

或者,你可能需要實現Basic Auth,這里有一個內置的基礎校驗攔截器?BasicAuthRequestInterceptor

Bank bank = Feign.builder().decoder(accountDecoder).requestInterceptor(new BasicAuthRequestInterceptor(username, password)).target(Bank.class, "https://api.examplebank.com");

Custom @Param Expansion

在使用?@Param?注解給模板中的參數設值的時候,默認的是使用的對象的?toString()?方法的值,通過聲明 自定義的Param.Expander,用戶可以控制其行為,比如說格式化?Date?類型的值:

// 通過設置 @Param 的 expander 為 DateToMillis.class 可以定義Date類型的值
@RequestLine("GET /?since={date}") 
Result list(@Param(value = "date", expander = DateToMillis.class) Date date);

Dynamic Query Parameters

動態查詢參數支持,通過使用?@QueryMap?可以允許動態傳入請求參數,如下:

@RequestLine("GET /find")
V find(@QueryMap Map<String, Object> queryMap);

Static and Default Methods

如果你使用的是JDK 1.8+ 的話,那么你可以給接口設置統一的默認方法和靜態方法,這個事JDK8的新特性,如下:

interface GitHub {@RequestLine("GET /repos/{owner}/{repo}/contributors")List<Contributor> contributors(@Param("owner") String owner, @Param("repo") String repo); @RequestLine("GET /users/{username}/repos?sort={sort}") List<Repo> repos(@Param("username") String owner, @Param("sort") String sort); default List<Repo> repos(String owner) { return repos(owner, "full_name"); } /** * Lists all contributors for all repos owned by a user. */ default List<Contributor> contributors(String user) { MergingContributorList contributors = new MergingContributorList(); for(Repo repo : this.repos(owner)) { contributors.addAll(this.contributors(user, repo.getName())); } return contributors.mergeResult(); } static GitHub connect() { return Feign.builder() .decoder(new GsonDecoder()) .target(GitHub.class, "https://api.github.com"); } }

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/450384.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/450384.shtml
英文地址,請注明出處:http://en.pswp.cn/news/450384.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

預處理

C語言##預算符 和#運算符一樣&#xff0c;##運算符可以用于宏函數的替換部分。這個運算符把兩個語言符號組合成單個語言符號。看例子&#xff1a;#define XNAME(n) x ## n如果這樣使用宏&#xff1a;XNAME(8)則會被展開成這樣&#xff1a;x8看明白了沒&#xff1f; ##就是個粘合…

Lambda表達式使用2

1.概述    本篇主要介紹lambda中常用的收集器&#xff0c;收集器的作用就是從數據流中生成需要的數據接口。    最常用的就是Collectors.toList()&#xff0c;只要將它傳遞給collect()函數&#xff0c;就能夠使用它了。    在我們使用收集器的時候經常會用到“方法…

notepad++ 使用去掉自動檢查紅線

前些天發現了一個巨牛的人工智能學習網站&#xff0c;通俗易懂&#xff0c;風趣幽默&#xff0c;忍不住分享一下給大家。點擊跳轉到教程。 notepad新升級了之后就有自動判斷的紅線&#xff0c;單詞拼錯了就給提示&#xff0c;看著這紅線實在難受 在 菜單選項&#xff1a;[插件…

cAdvisor+InfluxDB+Grafana 監控Docker

容器的監控方案其實有很多&#xff0c;有docker自身的docker stats命令、有Scout、有Data Dog等等&#xff0c;本文主要和大家分享一下比較經典的容器開源監控方案組合&#xff1a;cAdvisorInfluxDBGrafan 一、概念 1). InfluxDB是什么nfluxDB是用GO語言編寫的一個開源分布式時…

C語言return關鍵字

return 用來終止一個函數并返回其后面跟著的值。return &#xff08;Val&#xff09;&#xff1b;//此括號可以省略。但一般不省略&#xff0c;尤其在返回一個表達式的值時。return 可以返回些什么東西呢&#xff1f;看下面例子&#xff1a;char * Func(void){char str[30];…r…

win7旗艦版怎么降級到專業版

一、操作準備及注意事項 1、UltraISO光盤制作工具9.5 2、備份C盤及桌面文件 二、win7旗艦版改成專業版的步驟 1、當前系統為Win7 SP1 64位旗艦版&#xff1b; 2、按WinR打開運行&#xff0c;輸入regedit打開注冊表編輯器&#xff0c;定位到HKEY_LOCAL_MACHINE\Software\Microso…

JPA criteria 查詢:類型安全與面向對象

前些天發現了一個巨牛的人工智能學習網站&#xff0c;通俗易懂&#xff0c;風趣幽默&#xff0c;忍不住分享一下給大家。點擊跳轉到教程。 JPA的標準查詢,名為:JPA criteria查詢. 相比JPQL,其優勢是類型安全,更加的面向對象.使用標準查詢,開發人員可在編譯的時候就檢查 查詢的…

Algs4-1.4.18數組的局部最小元素

1.4.18數組的局部最小元素。編寫一個程序&#xff0c;給定一個含有N個不同整數的數組&#xff0c;找到一個局部最小元素:滿足a[i]<a[i-1],且a[i]<a[i1]的索引i。程序在最壞情況下所需的比較次數為~2lgN。答&#xff1a;檢查數組的中間值a[N/2]以及和它相鄰的元素a[N/2-1]…

編程技能和做員工的技能——哪個更重要?

摘要&#xff1a;不管我們程序員如何認識這個問題&#xff0c;如果你想在給別人編程打工中獲得事業成功&#xff0c;編程技能不是第一重要的。學會如何做一個好的員工才是重要的&#xff0c;甚至是非常重要的。從最最基本的層面上講&#xff0c;每個員工都應該為最求兩種基本的…

nginx-exporter安裝使用

一、沒有vts的啟動方式 #nginx_exporter -telemetry.address:9113 -nginx.scrape_uri"http://127.0.0.1:10000/nginx_statusnginx_exporter -telemetry.address:9113 -nginx.scrape_uri"https://xx.xx.xx.xx:18443" -insecure #端口9113應該是nginx_exporter監…

spring data jpa 的 in 查詢 Specification 實現

前些天發現了一個巨牛的人工智能學習網站&#xff0c;通俗易懂&#xff0c;風趣幽默&#xff0c;忍不住分享一下給大家。點擊跳轉到教程。 只是一個簡單需求&#xff1a; 查詢所有部門id 屬于 idList 的數據 Page<WorkWeight> page workWeightRepository.findAll(new…

在移動互聯網上賺錢,行不行

移動互聯網已被證實是互聯網產業發展的大趨勢。不過&#xff0c;究竟如何賺錢&#xff0c;對海外企業與中國企業來說都是難題。本月初&#xff0c;幾位業界大佬與風投來了一番討論&#xff0c;議題還是一個“在移動互聯網上賺錢&#xff0c;行還是不行”。 百度試圖通過用戶習慣…

計算機網絡知識簡單介紹

一、網絡基礎 1.網絡指的是什么&#xff1f; 計算機與計算機之間通過物理鏈接介質&#xff08;網絡設備&#xff09;連接到一起。 計算機與計算機之間基于網絡協議通信&#xff08;網絡協議就相當于計算機界的英語&#xff09; 2.osi七層協議&#xff1a; 互聯網協議按照功能不…

Linux下安裝FFmpeg

FFmpeg官網&#xff1a;http://www.ffmpeg.org 官網介紹 FFmpeg is the leading multimedia framework, able to decode, encode, transcode, mux, demux, stream, filter and play pretty much anything that humans and machines have created. It supports the most obscure…

HTTP協議狀態碼詳解

前些天發現了一個巨牛的人工智能學習網站&#xff0c;通俗易懂&#xff0c;風趣幽默&#xff0c;忍不住分享一下給大家。點擊跳轉到教程。 狀態碼含義100客戶端應當繼續發送請求。這個臨時響應是用來通知客戶端它的部分請求已經被服務器接收&#xff0c;且仍未被拒絕。客戶端應…

【Python web 開發】viewset 實現商品詳情頁的接口

我們如何來完成商品詳情頁的接口呢&#xff1f; 首先要配置一個商品詳情的url 按照我們正常的接口配法 &#xff0c;應該是后面要加一個id 的&#xff0c;為什么這里沒有加id 呢? ,應該是rooter register 的作用吧&#xff0c;等我在學習一遍基礎再來回答&#xff1f; 那么我…

Ignite中的機器學習介紹

為什么80%的碼農都做不了架構師&#xff1f;>>> 本系列共6篇文章&#xff0c;會通過一些代碼示例&#xff0c;講解如何在Ignite中使用機器學習庫&#xff0c;本文是本系列的第一篇。 從Ignite的2.4版本開始&#xff0c;機器學習就可以用于生產環境了。在這個版本中…

4G發牌或提早 電信聯通面臨艱難抉擇

曾幾何時遙不可及的4G&#xff0c;上馬的時間可能要比預期來的要早。今年3月&#xff0c;工信部部長苗圩表示&#xff0c;預計國內需要2-3年才會發放4G牌照。話音猶在耳&#xff0c;苗圩部長9月11日表示&#xff0c;“工信部已決定將于一年左右的時間發放TD-LTE牌照”。 工信部…

mysql 的 sql 執行計劃詳解

前些天發現了一個巨牛的人工智能學習網站&#xff0c;通俗易懂&#xff0c;風趣幽默&#xff0c;忍不住分享一下給大家。點擊跳轉到教程。 引言&#xff1a; 實際項目開發中&#xff0c;由于我們不知道實際查詢的時候數據庫里發生了什么事情&#xff0c;數據庫軟件是怎樣掃描…

2018-10-28

我的博客即將入駐“云棲社區”&#xff0c;誠邀技術同仁一同入駐。