欧美一区二区三区老妇人-欧美做爰猛烈大尺度电-99久久夜色精品国产亚洲a-亚洲福利视频一区二区

OpenFeign基本介紹和原理了解-創(chuàng)新互聯(lián)

了解 OpenFeign

OpenFeign 組件的前身是 Netflix Feign 項(xiàng)目。后來(lái) Feign 項(xiàng)目被貢獻(xiàn)給了開源組織,才有了今天使用的 Spring Cloud OpenFeign 組件。
OpenFeign 提供了一種聲明式的遠(yuǎn)程調(diào)用接口,它可以大幅簡(jiǎn)化遠(yuǎn)程調(diào)用的編程體驗(yàn)。用一個(gè)代碼片段看一下,由 OpenFeign 發(fā)起的遠(yuǎn)程服務(wù)調(diào)用的代碼風(fēng)格是什么樣的。

創(chuàng)新互聯(lián)建站是一家網(wǎng)站設(shè)計(jì)公司,集創(chuàng)意、互聯(lián)網(wǎng)應(yīng)用、軟件技術(shù)為一體的創(chuàng)意網(wǎng)站建設(shè)服務(wù)商,主營(yíng)產(chǎn)品:成都響應(yīng)式網(wǎng)站建設(shè)公司品牌網(wǎng)站制作全網(wǎng)整合營(yíng)銷推廣。我們專注企業(yè)品牌在網(wǎng)站中的整體樹立,網(wǎng)絡(luò)互動(dòng)的體驗(yàn),以及在手機(jī)等移動(dòng)端的優(yōu)質(zhì)呈現(xiàn)。做網(wǎng)站、成都網(wǎng)站建設(shè)、移動(dòng)互聯(lián)產(chǎn)品、網(wǎng)絡(luò)運(yùn)營(yíng)、VI設(shè)計(jì)、云產(chǎn)品.運(yùn)維為核心業(yè)務(wù)。為用戶提供一站式解決方案,我們深知市場(chǎng)的競(jìng)爭(zhēng)激烈,認(rèn)真對(duì)待每位客戶,為客戶提供賞析悅目的作品,網(wǎng)站的價(jià)值服務(wù)。
String response = helloWorldService.hello("Spring Cloud");

可以發(fā)現(xiàn),使用 OpenFeign 組件來(lái)實(shí)現(xiàn)遠(yuǎn)程調(diào)用非常簡(jiǎn)單,就像使用本地方法一樣,只要一行代碼就能實(shí)現(xiàn) WebClient 組件好幾行代碼干的事情。而且這段代碼不包含任何業(yè)務(wù)無(wú)關(guān)的信息,完美實(shí)現(xiàn)了調(diào)用邏輯和業(yè)務(wù)邏輯之間的職責(zé)分離。

OpenFeign 組件背后的工作流程

OpenFeign 使用了一種動(dòng)態(tài)代理技術(shù)來(lái)封裝遠(yuǎn)程服務(wù)調(diào)用的過程,在上面的例子中看到的 helloWorldService 其實(shí)是一個(gè)特殊的接口,它是由 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);
}

遠(yuǎn)程服務(wù)調(diào)用的信息被寫在了 FeignClient 接口中。在上面的代碼里,可以看到,服務(wù)的名稱、接口類型、訪問路徑已經(jīng)通過注解做了聲明。OpenFeign 通過解析這些注解標(biāo)簽生成一個(gè)動(dòng)態(tài)代理類,這個(gè)代理類會(huì)將接口調(diào)用轉(zhuǎn)化為一個(gè)遠(yuǎn)程服務(wù)調(diào)用的 Request,并發(fā)送給目標(biāo)服務(wù)。

OpenFeign 的動(dòng)態(tài)代理

在項(xiàng)目初始化階段,OpenFeign 會(huì)生成一個(gè)代理類,對(duì)所有通過FeignClient 接口發(fā)起的遠(yuǎn)程調(diào)用進(jìn)行動(dòng)態(tài)代理。如圖:
在這里插入圖片描述
上圖中的步驟中,在項(xiàng)目啟動(dòng)階段加載完成的是 1 ~ 3步 ,只有第 4 步(調(diào)用遠(yuǎn)程服務(wù))是發(fā)生在項(xiàng)目的運(yùn)行階段。
關(guān)鍵步驟描述:

  1. 在項(xiàng)目啟動(dòng)階段,OpenFeign 框架會(huì)發(fā)起一個(gè)主動(dòng)的掃包流程,從指定的目錄下掃描并加載所有被 @FeignClient 注解修飾的接口。
  2. OpenFeign 會(huì)針對(duì)每一個(gè) FeignClient 接口生成一個(gè)動(dòng)態(tài)代理對(duì)象,即圖中的 FeignProxyService,這個(gè)代理對(duì)象在繼承關(guān)系上屬于 FeignClient 注解所修飾的接口的實(shí)例。
  3. 這個(gè)動(dòng)態(tài)代理對(duì)象會(huì)被添加到 Spring 上下文中,并注入到對(duì)應(yīng)的服務(wù)里,也就是圖中的 LocalService 服務(wù)。
  4. LocalService 會(huì)發(fā)起底層方法調(diào)用。實(shí)際上這個(gè)方法調(diào)用會(huì)被 OpenFeign 生成的代理對(duì)象接管,由代理對(duì)象發(fā)起一個(gè)遠(yuǎn)程服務(wù)調(diào)用,并將調(diào)用的結(jié)果返回給 LocalService。
OpenFeign 是如何通過動(dòng)態(tài)代理技術(shù)創(chuàng)建代理對(duì)象的?

OpenFeign 組件加載過程的重要階段,如圖:
在這里插入圖片描述
OpenFeign 動(dòng)態(tài)代理類的創(chuàng)建過程:

  1. 項(xiàng)目加載:在項(xiàng)目的啟動(dòng)階段,EnableFeignClients 注解扮演了啟動(dòng)開關(guān)的角色,它使用 Spring 框架的 Import 注解導(dǎo)入了 FeignClientsRegistrar 類,開始了 OpenFeign 組件的加載過程。
@SpringBootApplication
@EnableFeignClients
public class HelloWorldApplication {public static void main(String[] args) {SpringApplication.run(HelloWorldApplication .class, args);
    }

}
  1. 掃包:FeignClientsRegistrar 負(fù)責(zé) FeignClient 接口的加載,它會(huì)在指定的包路徑下掃描所有的 FeignClients 類,并構(gòu)造 FeignClientFactoryBean 對(duì)象來(lái)解析 FeignClient 接口。
  2. 解析 FeignClient 注解:FeignClientFactoryBean 有兩個(gè)重要的功能,一個(gè)是解析 FeignClient 接口中的請(qǐng)求路徑和降級(jí)函數(shù)的配置信息;另一個(gè)是觸發(fā)動(dòng)態(tài)代理的構(gòu)造過程。
  3. 構(gòu)建動(dòng)態(tài)代理對(duì)象:ReflectiveFeign 包含了 OpenFeign 動(dòng)態(tài)代理的核心邏輯,它主要負(fù)責(zé)創(chuàng)建出 FeignClient 接口的動(dòng)態(tài)代理對(duì)象。ReflectiveFeign 在這個(gè)過程中有兩個(gè)重要任務(wù):一個(gè)是解析 FeignClient 接口上各個(gè)方法級(jí)別的注解。將其中的遠(yuǎn)程接口 URL、接口類型(GET、POST 等)、各個(gè)請(qǐng)求參數(shù)等封裝成元數(shù)據(jù),并為每一個(gè)方法生成一個(gè)對(duì)應(yīng)的 MethodHandler 類作為方法級(jí)別的代理;另一個(gè)重要任務(wù)是將這些 MethodHandler 方法代理做進(jìn)一步封裝,通過 Java 標(biāo)準(zhǔn)的動(dòng)態(tài)代理協(xié)議,構(gòu)建一個(gè)實(shí)現(xiàn)了 InvocationHandler 接口的動(dòng)態(tài)代理對(duì)象,并將這個(gè)動(dòng)態(tài)代理對(duì)象綁定到 FeignClient 接口上。這樣一來(lái),所有發(fā)生在 FeignClient 接口上的調(diào)用,最終都會(huì)由它背后的動(dòng)態(tài)代理對(duì)象來(lái)承接。
    MethodHandler 的構(gòu)建過程涉及到了復(fù)雜的元數(shù)據(jù)解析,OpenFeign 組件將 FeignClient 接口上的各種注解封裝成元數(shù)據(jù),并利用這些元數(shù)據(jù)把一個(gè)方法調(diào)用“翻譯”成一個(gè)遠(yuǎn)程調(diào)用的 Request 請(qǐng)求。
    元數(shù)據(jù)的解析是依賴于 OpenFeign 組件中的 Contract 協(xié)議解析功能。Contract 是 OpenFeign 組件中定義的頂層抽象接口,它有一系列的具體實(shí)現(xiàn),其中 SpringMvcContract 這個(gè)類名字中就能看出來(lái),它是專門用來(lái)解析 Spring MVC 標(biāo)簽的。
    SpringMvcContract 的繼承結(jié)構(gòu)是 :SpringMvcContract->BaseContract->Contract。
    這里拿一段 SpringMvcContract 的代碼塊,理解它是如何將注解解析為元數(shù)據(jù)的。這段代碼的主要功能是解析 FeignClient 方法級(jí)別上定義的 Spring MVC 注解。
// 解析FeignClient接口方法級(jí)別上的RequestMapping注解
protected void processAnnotationOnMethod(MethodMetadata data, Annotation methodAnnotation, Method method) {   // 如果方法上沒有使用RequestMapping注解,則不進(jìn)行解析
   // 其實(shí)GetMapping、PostMapping等注解都屬于RequestMapping注解
   if (!RequestMapping.class.isInstance(methodAnnotation)
         && !methodAnnotation.annotationType().isAnnotationPresent(RequestMapping.class)) {  return;
   }

   // 獲取RequestMapping注解實(shí)例
   RequestMapping methodMapping = findMergedAnnotation(method, RequestMapping.class);
   // 解析Http Method定義,即注解中的GET、POST、PUT、DELETE方法類型
   RequestMethod[] methods = methodMapping.method();
   // 如果沒有定義methods屬性則默認(rèn)當(dāng)前方法是個(gè)GET方法
   if (methods.length == 0) {  methods = new RequestMethod[] {RequestMethod.GET };
   }
   checkOne(method, methods, "method");
   data.template().method(Request.HttpMethod.valueOf(methods[0].name()));

   // 解析Path屬性,即方法上寫明的請(qǐng)求路徑
   checkAtMostOne(method, methodMapping.value(), "value");
   if (methodMapping.value().length >0) {  String pathValue = emptyToNull(methodMapping.value()[0]);
      if (pathValue != null) { pathValue = resolve(pathValue);
         // 如果path沒有以斜杠開頭,則補(bǔ)上/
         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 對(duì) RequestMappings 注解的各個(gè)屬性都做了解析。
如果項(xiàng)目中使用的是 GetMapping、PostMapping 之類的注解,沒有使用 RequestMapping,那么 OpenFeign 也可以解析。以 GetMapping 為例,它對(duì) RequestMapping 注解做了一層封裝。如下代碼片段,這個(gè)注解頭上也掛了一個(gè) RequestMapping 注解。因此 OpenFeign 可以正確識(shí)別 GetMapping 并完成加載。

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@RequestMapping(method = RequestMethod.GET)
public @interface GetMapping {// ...省略部分代碼
}
OpenFeign調(diào)用過程

OpenFeign 其實(shí)底層調(diào)用的是 Feign 的方法,生成了代理類,使用的是 JDK 的動(dòng)態(tài)代理,然后 bean 注入。
調(diào)用過程,就是代理類作為客戶端向被調(diào)用方發(fā)送請(qǐng)求,接收相應(yīng)的過程。其中,feign 自行封裝了 JDK java.net 相關(guān)的網(wǎng)絡(luò)請(qǐng)求方法,請(qǐng)求過程中還有 Loadbalancer 進(jìn)行負(fù)載均衡;收到響應(yīng)后,還會(huì)對(duì)響應(yīng)類進(jìn)行解析,取出正確的響應(yīng)信息。

你是否還在尋找穩(wěn)定的海外服務(wù)器提供商?創(chuàng)新互聯(lián)www.cdcxhl.cn海外機(jī)房具備T級(jí)流量清洗系統(tǒng)配攻擊溯源,準(zhǔn)確流量調(diào)度確保服務(wù)器高可用性,企業(yè)級(jí)服務(wù)器適合批量采購(gòu),新人活動(dòng)首月15元起,快前往官網(wǎng)查看詳情吧

本文名稱:OpenFeign基本介紹和原理了解-創(chuàng)新互聯(lián)
網(wǎng)頁(yè)URL:http://chinadenli.net/article40/gdpho.html

成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供網(wǎng)站內(nèi)鏈全網(wǎng)營(yíng)銷推廣云服務(wù)器品牌網(wǎng)站建設(shè)網(wǎng)站導(dǎo)航外貿(mào)網(wǎng)站建設(shè)

廣告

聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請(qǐng)盡快告知,我們將會(huì)在第一時(shí)間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如需處理請(qǐng)聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來(lái)源: 創(chuàng)新互聯(lián)

營(yíng)銷型網(wǎng)站建設(shè)