OpenFeign 組件的前身是 Netflix Feign 項目。后來 Feign 項目被貢獻給了開源組織,才有了今天使用的 Spring Cloud OpenFeign 組件。
OpenFeign 提供了一種聲明式的遠程調用接口,它可以大幅簡化遠程調用的編程體驗。用一個代碼片段看一下,由 OpenFeign 發(fā)起的遠程服務調用的代碼風格是什么樣的。
String response = helloWorldService.hello("Spring Cloud");
可以發(fā)現(xiàn),使用 OpenFeign 組件來實現(xiàn)遠程調用非常簡單,就像使用本地方法一樣,只要一行代碼就能實現(xiàn) WebClient 組件好幾行代碼干的事情。而且這段代碼不包含任何業(yè)務無關的信息,完美實現(xiàn)了調用邏輯和業(yè)務邏輯之間的職責分離。
OpenFeign 組件背后的工作流程OpenFeign 使用了一種動態(tài)代理技術來封裝遠程服務調用的過程,在上面的例子中看到的 helloWorldService 其實是一個特殊的接口,它是由 OpenFeign 組件中的 FeignClient 注解所聲明的接口。
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.*;
@FeignClient(value = "hello-world-service")
public interface HelloWorldService { @PostMapping("/sayHello")
String hello(String guestName);
}
遠程服務調用的信息被寫在了 FeignClient 接口中。在上面的代碼里,可以看到,服務的名稱、接口類型、訪問路徑已經通過注解做了聲明。OpenFeign 通過解析這些注解標簽生成一個動態(tài)代理類,這個代理類會將接口調用轉化為一個遠程服務調用的 Request,并發(fā)送給目標服務。
OpenFeign 的動態(tài)代理在項目初始化階段,OpenFeign 會生成一個代理類,對所有通過FeignClient 接口發(fā)起的遠程調用進行動態(tài)代理。如圖:
上圖中的步驟中,在項目啟動階段加載完成的是 1 ~ 3步 ,只有第 4 步(調用遠程服務)是發(fā)生在項目的運行階段。
關鍵步驟描述:
OpenFeign 組件加載過程的重要階段,如圖:
OpenFeign 動態(tài)代理類的創(chuàng)建過程:
@SpringBootApplication
@EnableFeignClients
public class HelloWorldApplication {public static void main(String[] args) {SpringApplication.run(HelloWorldApplication .class, args);
}
}
// 解析FeignClient接口方法級別上的RequestMapping注解
protected void processAnnotationOnMethod(MethodMetadata data, Annotation methodAnnotation, Method method) { // 如果方法上沒有使用RequestMapping注解,則不進行解析
// 其實GetMapping、PostMapping等注解都屬于RequestMapping注解
if (!RequestMapping.class.isInstance(methodAnnotation)
&& !methodAnnotation.annotationType().isAnnotationPresent(RequestMapping.class)) { return;
}
// 獲取RequestMapping注解實例
RequestMapping methodMapping = findMergedAnnotation(method, RequestMapping.class);
// 解析Http Method定義,即注解中的GET、POST、PUT、DELETE方法類型
RequestMethod[] methods = methodMapping.method();
// 如果沒有定義methods屬性則默認當前方法是個GET方法
if (methods.length == 0) { methods = new RequestMethod[] {RequestMethod.GET };
}
checkOne(method, methods, "method");
data.template().method(Request.HttpMethod.valueOf(methods[0].name()));
// 解析Path屬性,即方法上寫明的請求路徑
checkAtMostOne(method, methodMapping.value(), "value");
if (methodMapping.value().length >0) { String pathValue = emptyToNull(methodMapping.value()[0]);
if (pathValue != null) { pathValue = resolve(pathValue);
// 如果path沒有以斜杠開頭,則補上/
if (!pathValue.startsWith("/") && !data.template().path().endsWith("/")) {pathValue = "/" + pathValue;
}
data.template().uri(pathValue, true);
if (data.template().decodeSlash() != decodeSlash) {data.template().decodeSlash(decodeSlash);
}
}
}
// 解析RequestMapping中定義的produces屬性
parseProduces(data, method, methodMapping);
// 解析RequestMapping中定義的consumer屬性
parseConsumes(data, method, methodMapping);
// 解析RequestMapping中定義的headers屬性
parseHeaders(data, method, methodMapping);
data.indexToExpander(new LinkedHashMap<>());
}
通過上面的方法可以看到,OpenFeign 對 RequestMappings 注解的各個屬性都做了解析。
如果項目中使用的是 GetMapping、PostMapping 之類的注解,沒有使用 RequestMapping,那么 OpenFeign 也可以解析。以 GetMapping 為例,它對 RequestMapping 注解做了一層封裝。如下代碼片段,這個注解頭上也掛了一個 RequestMapping 注解。因此 OpenFeign 可以正確識別 GetMapping 并完成加載。
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@RequestMapping(method = RequestMethod.GET)
public @interface GetMapping {// ...省略部分代碼
}
OpenFeign調用過程OpenFeign 其實底層調用的是 Feign 的方法,生成了代理類,使用的是 JDK 的動態(tài)代理,然后 bean 注入。
調用過程,就是代理類作為客戶端向被調用方發(fā)送請求,接收相應的過程。其中,feign 自行封裝了 JDK java.net 相關的網(wǎng)絡請求方法,請求過程中還有 Loadbalancer 進行負載均衡;收到響應后,還會對響應類進行解析,取出正確的響應信息。
你是否還在尋找穩(wěn)定的海外服務器提供商?創(chuàng)新互聯(lián)www.cdcxhl.cn海外機房具備T級流量清洗系統(tǒng)配攻擊溯源,準確流量調度確保服務器高可用性,企業(yè)級服務器適合批量采購,新人活動首月15元起,快前往官網(wǎng)查看詳情吧
本文名稱:OpenFeign基本介紹和原理了解-創(chuàng)新互聯(lián)
網(wǎng)頁URL:http://aaarwkj.com/article40/gdpho.html
成都網(wǎng)站建設公司_創(chuàng)新互聯(lián),為您提供網(wǎng)站內鏈、全網(wǎng)營銷推廣、云服務器、品牌網(wǎng)站建設、網(wǎng)站導航、外貿網(wǎng)站建設
聲明:本網(wǎng)站發(fā)布的內容(圖片、視頻和文字)以用戶投稿、用戶轉載內容為主,如果涉及侵權請盡快告知,我們將會在第一時間刪除。文章觀點不代表本網(wǎng)站立場,如需處理請聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內容未經允許不得轉載,或轉載時需注明來源: 創(chuàng)新互聯(lián)