feign入門教程

feign入門教程

1.介紹

feign簡單來說是一個java http客戶端,用來減少http API調用的複雜性。spring-Cloud-Netflix中就集成了feign客戶端用來訪問遠程的http服務,不管是用來作爲遠程調用客戶端,還是api接口測試都是非常方便的。
這裏要講的主要是OpenFeign。首先來看一下簡單的操作例子


2.示例

interface GitHub {
  @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 + ")");
  }
}

@RequestLine定義了請求的http方法爲GET,uri爲/repos/{owner}/{repo}/contributors,{}中的參數會被@Param註解的參數所替換請求的url爲https://api.github.com。feign訪問此接口後會將返回的值轉換成List類型。


3.客戶端構建

feign客戶端使用builder模式構建,可以設置logLevel、contract、client、logger、encoder、decoder等配置。其中比較重要的

  • encoder decoder 數據編解碼器
  • client 配置發送http的客戶端。
  • logLevel 配置日誌等級爲不輸出日誌、基礎日誌、輸出http頭、全部日誌


3.1 encoder decoder

feign默認使用第三方工具實現了很多編解碼器,如gson、jackson、Sax、JAXB
* 使用gson進行json序列化、反序化

GsonCodec codec = new GsonCodec();
GitHub github = Feign.builder()
                     .encoder(new GsonEncoder())
                     .decoder(new GsonDecoder())
                     .target(GitHub.class, "https://api.github.com");
  • 使用Jackson進行json序列化、反序化
GitHub github = Feign.builder()
                     .encoder(new JacksonEncoder())
                     .decoder(new JacksonDecoder())
                     .target(GitHub.class, "https://api.github.com");
  • 使用SAX進行xml反序化
api = Feign.builder()
           .decoder(SAXDecoder.builder()
           .registerContentHandler(UserIdHandler.class)
           .build())
           .target(Api.class, "https://apihost");
  • 使用JAXB訪問xml api
api = Feign.builder()
           .encoder(new JAXBEncoder())
           .decoder(new JAXBDecoder())
           .target(Api.class, "https://apihost");


3.2 client

  • 使用OkHttp 客戶端進行http訪問
GitHub github = Feign.builder()
                     .client(new OkHttpClient())
                     .target(GitHub.class, "https://api.github.com");
  • 使用Ribbon 客戶端進行http訪問,可以使用ribbon的路由功能
MyService api = Feign.builder().client(RibbonClient.create()).target(MyService.class, "https://myAppProd");
  • 使用熔斷器Hystrix客戶端進行http訪問
MyService api = HystrixFeign.builder().target(MyService.class, "https://myAppProd");

其他一些第三方實現就不多說了,自己可以去github查找


4.feign註解

  • @Param 需要發送的http參數,可以替換其他註解上的參數。如@RequestLine中uri參數 @Body中的請求體
  • @Headers 定義http請求的請求頭 如定義content type @Headers(“Content-Type: application/x-www-form-urlencoded”)
  • @RequestLine 定義http的請求行,定義了訪問和uri
  • @Body 定義請體的模板,使用@Param參數替換
  • @QueryMap 使用map作爲請求的參數鍵值對
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!
  @Body("%7B\"user_name\": \"{user_name}\", \"password\": \"{password}\"%7D")
  void json(@Param("user_name") String user, @Param("password") String password);
}
...
client.xml("denominator", "secret"); // <login "user_name"="denominator" "password"="secret"/>
client.json("denominator", "secret"); // {"user_name": "denominator", "password": "secret"}

5.其他特性

5.1 接口繼承

對於一些通用的接口,uri相同,只有域名不同,可以使用帶泛型的接口的繼承特性,

interface BaseAPI {
  @RequestLine("GET /health")
  String health();

  @RequestLine("GET /all")
  List<Entity> all();
}

interface CustomAPI extends BaseAPI {
  @RequestLine("GET /custom")
  String custom();
}
@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> { }

5.2請求攔截器

實現RequestInterceptor接口在feign build的時候可以設置此攔截器,但是貌似並沒有攔截功能,只能添加一些共用的代碼
想要時間攔截可能需要拋出異常,中斷請求。
如添加一些公用頭部

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");

5.3 參數toString

@Param註解的參數默認使用ToStringExpander轉化爲String
可以在@Param中定義expander,實現public String expand(Object value) 方法。

@RequestLine("GET /?since={date}") Result list(@Param(value = "date", expander = DateToMillis.class) Date date);
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章