【Fegin技術專題】「原生態」開啟Fegin之RPC技術的開端,你會使用原生態的Fegin嗎?(高階用法)
theme: smartblue
本文已參與「掘力星計劃」,贏取創作大禮包,挑戰創作激勵金。
對於Httpclient請求機制進行設定操作處理。
@Body請求體模板
@Body註解申明一個請求體模板,模板中可以帶有引數,與方法中@Param註解申明的引數相匹配,使用方法如下:
java
interface LoginClient {
@RequestLine("POST /")
@Headers("Content-Type: application/json")
// json curly braces must be escaped!
// 這裡JSON格式需要的花括號居然需要轉碼,有點蛋疼了。
@Body("%7B\"user_name\": \"{user_name}\", \"password\": \"{password}\"%7D")
void login(@Param("user_name") String user, @Param("password") String password);
}
...
client.login("denominator", "secret");
// {"user_name": "denominator", "password": "secret"}
Headers請求頭
Feign支援給請求的api設定或者請求的客戶端設定請求頭,如下:
給API設定請求頭
使用 @Headers 設定靜態請求頭
java
// 給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);
}
設定動態值的請求頭
java
@RequestLine("POST /")
@Headers("X-Ping: {token}")
void post(@Param("token") String token);
設定key和value都是動態的請求頭
呼叫時動態確定使用不同的請求頭
可以使用 @HeaderMap 註解,如下:
java
// @HeaderMap 註解設定的請求頭優先於其他方式設定的
@RequestLine("POST /")
void post(@HeaderMap Map<String, Object> headerMap);
給Target設定請求頭
有時我們需要在一個API實現中根據不同的endpoint來傳入不同的Header,這個時候我們可以使用自定義的RequestInterceptor 或 Target來實現.
通過自定義的 RequestInterceptor 來實現請檢視 Request Interceptors
下面是一個通過自定義Target來實現給每個Target設定安全校驗資訊Header的例子:
java
static class DynamicAuthTokenTarget<T> implements Target<T> {
public DynamicAuthTokenTarget(Class<T> clazz,
UrlAndTokenProvider provider,
ThreadLocal<String> requestIdProvider);
...
@Override
public 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
有些請求中的一些方法是通用的,但是可能會有不同的引數型別或者返回型別,這個時候可以這麼用:
```java
// 通用API
interface BaseAPI {
@RequestLine("GET /health")
String health();
@RequestLine("GET /all")
List
```
Logging
你可以通過設定一個 Logger 來記錄http訊息,如下:
java
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);
Request Interceptors
當你希望修改所有的的請求的時候,你可以使用Request Interceptors。比如說,你作為一箇中介,你可能需要為每個請求設定 X-Forwarded-For
java
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,這裡有一個內建的基礎校驗攔截器
java
BasicAuthRequestInterceptor
Bank bank = Feign.builder()
.decoder(accountDecoder)
.requestInterceptor(new BasicAuthRequestInterceptor(username, password))
.target(Bank.class, https://api.examplebank.com);
@Param Expansion
@Param 註解給模板中的引數設值的時候,預設的是使用的物件的 toString() 方法的值,通過宣告 自定義的Param.Expander,使用者可以控制其行為,比如說格式化 Date 型別的值:
java
// 通過設定 @Param 的 expander 為 DateToMillis.class 可以定義Date型別的值
@RequestLine("GET /?since={date}")
Result list(@Param(value = "date", expander = DateToMillis.class) Date date);
Dynamic Query Parameters
動態查詢引數支援,通過使用 @QueryMap 可以允許動態傳入請求引數,如下:
java
@RequestLine("GET /find")
V find(@QueryMap Map<String, Object> queryMap);
自定義註解掃描動態生成客戶端
原生Feign只能一次解析一個介面,生成對應的請求代理物件,如果一個包裡有多個呼叫介面就要多次解析非常麻煩。
擴充套件BeanFactoryPostProcessor介面、
自定義註解:在掃描介面的過程中,可以通過一個自定義註解,來區分Feign介面並且指定呼叫的服務Url
實現擴充套件容器
java
@Component
public class FeignClientRegister implements BeanFactoryPostProcessor{
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) {
List<String> classes = scan(scanPath);
if(classes==null){
return ;
}
Feign.Builder builder = getFeignBuilder();
if(classes.size()>0){
for (String claz : classes) {
Class<?> targetClass = null;
try {
targetClass = Class.forName(claz);
String url=targetClass.getAnnotation(FeignApi.class).serviceUrl();
if(url.indexOf("http://")!=0){
url="http://"+url;
}
Object target = builder.target(targetClass, url);
beanFactory.registerSingleton(targetClass.getName(), target);
} catch (Exception e) {
throw new RuntimeException(e.getMessage());
}
}
}
}
public Feign.Builder getFeignBuilder(){
Feign.Builder builder = Feign.builder()
.encoder(new JacksonEncoder())
.decoder(new JacksonDecoder())
.options(new Request.Options(1000, 3500))
.retryer(new Retryer.Default(5000, 5000, 3));
return builder;
}
public List<String> scan(String path){
ScanResult result = new FastClasspathScanner(path).matchClassesWithAnnotation(FeignApi.class, (Class<?> aClass) -> {
}).scan();
if(result!=null){
return result.getNamesOfAllInterfaceClasses();
}
return null;
}
}
- 完整秒殺架構的設計到技術關鍵點的“情報資訊”
- 獨一無二的「MySQL調優金字塔」相信也許你擁有了它,你就很可能擁有了全世界。
- 【MySQL技術之旅】(5)該換換你的資料庫版本了,讓我們一同迎接8.0的到來哦!(初探篇)
- ☕【Java技術指南】「Java8程式設計專題」讓你真正會用對Java新版日期時間API程式設計指南
- 【Fegin技術專題】「原生態」開啟Fegin之RPC技術的開端,你會使用原生態的Fegin嗎?(高階用法)
- 【優化技術專題】「執行緒間的高效能訊息框架」終極關注Disruptor的核心原始碼和Java8的@Contended偽共享指南
- 【優化技術專題】「執行緒間的高效能訊息框架」再次細節領略Disruptor的底層原理和優勢分析
- 【Zookeeper核心原理】Paxos協議的原理和實際執行中的應用流程分析
- ☕【Java技術指南】「JPA程式設計專題」讓你不再對JPA技術中的“持久化型註解”感到陌生了!
- Java技術開發專題系列之【Guava RateLimiter】針對於限流器的入門到精通(含原始碼分析介紹)
- ☕【Java技術指南】「JPA程式設計專題」讓你不再對JPA技術中的“持久化型註解”感到陌生了!
- 【Eureka技術指南】「SpringCloud」從原始碼層面讓你認識Eureka工作流程和運作機制(下)
- MySQL技術專題(6)這也許是你的知識盲區-MySQL主從架構以及[半同步機制]
- 優化技術專題-執行緒間的高效能訊息框架-深入淺出Disruptor的使用和原理
- ☕【Java技術指南】「併發程式設計專題」Fork/Join框架基本使用和原理探究(原理篇)
- ☕【Java技術指南】「併發程式設計專題」Guava RateLimiter針對於限流器的入門到精通(含原始碼分析介紹)
- 【優化技術專題】「溫故而知新」基於Quartz系列的任務排程框架的動態化任務實現分析
- ☕【Java技術指南】「併發程式設計專題」Guava RateLimiter針對於限流器的入門到精通(含實戰和原理分析)
- 【MySQL技術之旅】(4)這也許是你的知識盲區-[MySQL主從架構]之半同步機制
- ☕【Java技術指南】「併發程式設計專題」CompletionService框架基本使用和原理探究(基礎篇)