Spring?Cloud實現(xiàn)遠程調(diào)用OpenFeign組件的方法
一、RestTemplate存在問題
觀察之前文章介紹的遠程調(diào)用的代碼:
public OrderInfo selectOrderById(Integer orderId) {
OrderInfo orderInfo = orderMapper.selectOrderById(orderId);
String url = "http://product-service/product/"+ orderInfo.getProductId();
ProductInfo productInfo = restTemplate.getForObject(url,
ProductInfo.class);
orderInfo.setProductInfo(productInfo);
return orderInfo;
}
雖說RestTemplate 對HTTP封裝后, 已經(jīng)比直接使用HTTPClient簡單方便很多, 但是還存在一些問題.
- 需要拼接URL, 靈活性高, 但是封裝臃腫, URL復雜時, 容易出錯.
- 代碼可讀性差, 風格不統(tǒng)?.
微服務之間的通信方式, 通常有兩種: RPC 和 HTTP.
在SpringCloud中, 默認是使用HTTP來進行微服務的通信, 最常用的實現(xiàn)形式有兩種:
• RestTemplate
• OpenFeign
RPC(Remote Procedure Call)遠程過程調(diào)用,是?種通過網(wǎng)絡從遠程計算機上請求服務,而不需
要了解底層網(wǎng)絡通信細節(jié)。RPC可以使用多種網(wǎng)絡協(xié)議進行通信, 如HTTP、TCP、UDP等, 并且在
TCP/IP網(wǎng)絡四層模型中跨越了傳輸層和應用層。簡言之RPC就是像調(diào)用本地方法?樣調(diào)用遠程方法。
常見的RPC框架有:
1 . Dubbo: Apache Dubbo 中文
2 . Thrift : Apache Thrift - Home
3 . gRPC: gRPC
二、OpenFeign介紹
OpenFeign 是一個聲明式的 Web Service 客戶端. 它讓微服務之間的調(diào)用變得更簡單, 類似controller調(diào)用service, 只需要創(chuàng)建?個接口,然后添加注解即可使用OpenFeign.
OpenFeign 的前身
Feign 是 Netflix 公司開源的?個組件.
• 2013年6月, Netflix發(fā)布 Feign的第?個版本 1.0.0
• 2016年7月, Netflix發(fā)布Feign的最后?個版本 8.18.0
2016年,Netflix 將 Feign 捐獻給社區(qū)
• 2016年7月 OpenFeign 的首個版本 9.0.0 發(fā)布,之后?直持續(xù)發(fā)布到現(xiàn)在.
Spring Cloud Feign
Spring Cloud Feign 是 Spring 對 Feign 的封裝, 將 Feign 項目集成到 Spring Cloud ?態(tài)系統(tǒng)中.受 Feign 更名影響,Spring Cloud Feign 也有兩個 starter
spring-cloud-starter-feign
spring-cloud-starter-openfeign
由于Feign的停更維護, 對應的, 我們使用的依賴是 spring-cloud-starter-openfeign。
OpenFeign :官方文檔
Spring Cloud Feign:官方文檔
三、快速上手
3.1 引入依賴
<dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-openfeign</artifactId> </dependency>
3.2 添加注解
在order-service的啟動類添加注解 @EnableFeignClients , 開啟OpenFeign的功能.
@EnableFeignClients
@SpringBootApplication
public class OrderServiceApplication {
public static void main(String[] args) {
SpringApplication.run(OrderServiceApplication.class, args);
}
}
3.3 編寫OpenFeign的客戶端
基于SpringMVC的注解來聲明遠程調(diào)用的信息
@FeignClient(value = "product-service", path = "/product")
public interface ProductApi {
@RequestMapping("/{productId}")
ProductInfo getProductById(@PathVariable("productId") Integer productId);
}
@FeignClient 注解作用在接口上, 參數(shù)說明:
• name/value:指定FeignClient的名稱, 也就是微服務的名稱, 用于服務發(fā)現(xiàn), Feign底層會使用Spring Cloud LoadBalance進行負載均衡. 也可以使用 url 屬性指定?個具體的url.
• path: 定義當前FeignClient的統(tǒng)一前綴.
3.4 遠程調(diào)用
修改遠程調(diào)用的方法
@Autowired
private ProductApi productApi;
/**
* Feign實現(xiàn)遠程調(diào)?
* @param orderId
*/
public OrderInfo selectOrderById(Integer orderId) {
OrderInfo orderInfo = orderMapper.selectOrderById(orderId);
ProductInfo productInfo =
productApi.getProductById(orderInfo.getProductId());
orderInfo.setProductInfo(productInfo);
return orderInfo;
}
不同方式之間代碼對比:

四、OpenFeign參數(shù)傳遞
通過觀察, 我們也可以發(fā)現(xiàn), Feign的客戶端和服務提供者的接口聲明非常相似
上面例子中, 介紹了Feign 從URL中獲取參數(shù), 接下來介紹下Feign參數(shù)傳遞的其他方式。
4.1 傳遞單個參數(shù)
服務提供方:product-service
@RequestMapping("/product")
@RestController
public class ProductController {
@RequestMapping("/p1")
public String p1(Integer id){
return "p1接收到參數(shù):"+id;
}
}
Feign客戶端:
@FeignClient(value = "product-service", path = "/product")
public interface ProductApi {
@RequestMapping("/p1")
String p1(@RequestParam("id") Integer id);
}
服務消費方order-service:
@RequestMapping("/feign")
@RestController
public class TestFeignController {
@Autowired
private ProductApi productApi;
@RequestMapping("/o1")
public String o1(Integer id){
return productApi.p1(id);
}
}
測試遠程調(diào)用:
http://127.0.0.1:8080/feign/o1?id=5
測試結果:

4.2 傳遞多個參數(shù)
使用多個@RequestParam 進行參數(shù)綁定即可
服務提供方 product-service
@RequestMapping("/p2")
public String p2(Integer id,String name){
return "p2接收到參數(shù),id:"+id +",name:"+name;
}
Feign客戶端:
@FeignClient(value = "product-service", path = "/product")
public interface ProductApi {
@RequestMapping("/p2")
String p2(@RequestParam("id")Integer id,@RequestParam("name")String name);
}
服務消費方order-service:
@RequestMapping("/o2")
public String o2(@RequestParam("id")Integer id,@RequestParam("name")String name){
return productApi.p2(id,name);
}
測試遠程調(diào)用:
http://127.0.0.1:8080/feign/o2?id=5&name=zhangsan

4.3 傳遞對象
服務提供方 product-service
@RequestMapping("/p3")
public String p3(ProductInfo productInfo){
return "接收到對象, productInfo:"+productInfo;
}
Feign客戶端:
@RequestMapping("/p3")
String p3(@SpringQueryMap ProductInfo productInfo);
服務消費方order-service:
@RequestMapping("/o3")
public String o3(ProductInfo productInfo){
return productApi.p3(productInfo);
}
4.4 傳遞JSON
服務提供方 product-service:
@RequestMapping("/p4")
public String p4(@RequestBody ProductInfo productInfo){
return "接收到對象, productInfo:"+productInfo;
}
Feign客戶端
@RequestMapping("/p4")
String p4(@RequestBody ProductInfo productInfo);
服務消費方order-service:
@RequestMapping("/o4")
public String o4(@RequestBody ProductInfo productInfo){
System.out.println(productInfo.toString());
return productApi.p4(productInfo);
}
五、最佳實踐
最佳實踐, 其實也就是經(jīng)過歷史的迭代, 在項目中的實踐過程中, 總結出來的最好的使用方式.
通過觀察, 我們也能看出來, Feign的客戶端與服務提供者的controller代碼非常相似
Feign 客戶端:
@FeignClient(value = "product-service", path = "/product")
public interface ProductApi {
@RequestMapping("/{productId}")
ProductInfo getProductById(@PathVariable("productId") Integer productId);
}
服務提供方Controller:
@RequestMapping("/product")
@RestController
public class ProductController {
@RequestMapping("/{productId}")
public ProductInfo getProductById(@PathVariable("productId") Integer productId){
//...
}
}
有沒有?種方法可以簡化這種寫法呢?
5.1 Feign繼承方式
Feign 支持繼承的方式, 我們可以把?些常件的操作封裝到接口里.
我們可以定義好?個接口, 服務提供方實現(xiàn)這個接口, 服務消費方編寫Feign 接口的時候, 直接繼承這個接口
5.1.1 創(chuàng)建一個Module
接口可以放在?個公共的Jar包里, 供服務提供方和服務消費方使用

5.1.2 引入依賴
<dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-openfeign</artifactId> </dependency> </dependencies>
5.1.3 編寫接口
復制 ProductApi, ProductInfo 到product-api模塊中
public interface ProductInterface {
@RequestMapping("/{productId}")
ProductInfo getProductById(@PathVariable("productId") Integer productId);
@RequestMapping("/p1")
String p1(@RequestParam("id") Integer id);
@RequestMapping("/p2")
String p2(@RequestParam("id")Integer id,@RequestParam("name")String name);
@RequestMapping("/p3")
String p3(@SpringQueryMap ProductInfo productInfo);
@RequestMapping("/p4")
String p4(@RequestBody ProductInfo productInfo);
}
5.1.4 服務提供方
服務提供方實現(xiàn)接口ProductInterface:
@RequestMapping("/product")
@RestController
public class ProductController implements ProductInterface {
@Autowired
private ProductService productService;
@RequestMapping("/{productId}")
public ProductInfo getProductById(@PathVariable("productId") Integer
productId){
System.out.println("收到請求,Id:"+productId);
return productService.selectProductById(productId);
}
@RequestMapping("/p1")
public String p1(Integer id){
return "p1接收到參數(shù):"+id;
}
@RequestMapping("/p2")
public String p2(Integer id,String name){
return "p2接收到參數(shù),id:"+id +",name:"+name;
}
@RequestMapping("/p3")
public String p3(ProductInfo productInfo){
return "接收到對象, productInfo:"+productInfo;
}
@RequestMapping("/p4")
public String p4(@RequestBody ProductInfo productInfo){
return "接收到對象, productInfo:"+productInfo;
}
}
5.1.5 服務消費方
服務消費方繼承ProductInterface
@FeignClient(value = "product-service", path = "/product")
public interface ProductApi extends ProductInterface {
}
這樣通過繼承就可以實現(xiàn)遠程調(diào)用
5.2 Feign 抽取方式
官方推薦Feign的使用方式為繼承的方式, 但是企業(yè)開發(fā)中, 更多是把Feign接口抽取為?個獨立的模塊(做法和繼承相似, 但理念不同).
操作方法:
將Feign的Client抽取為?個獨立的模塊, 并把涉及到的實體類等都放在這個模塊中, 打成?個Jar. 服務消費方只需要依賴該Jar包即可. 這種方式在企業(yè)中比較常見, Jar包通常由服務提供方來實現(xiàn).
5.2.1 創(chuàng)建新module

5.2.2 引入依賴
<dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-openfeign</artifactId> </dependency>
5.2.3 編寫API
復制 ProductApi, ProductInfo 到product-api模塊中
之后通過Maven打包,可以觀察Maven本地倉庫檢查是否打包成功
5.2.4 服務消費方使用product-api
1 刪除 ProductApi, ProductInfo.
2. 引入依賴:
<dependency> <groupId>org.example</groupId> <artifactId>product-api</artifactId> <version>1.0-SNAPSHOT</version> </dependency>
修改項目中ProductApi, ProductInfo的路徑為product-api中的路徑
3 .指定掃描類: ProductApi
在啟動類添加掃描路徑
@EnableFeignClients(basePackages = {"com.bite.api"})
@SpringBootApplication
public class OrderServiceApplication {
public static void main(String[] args) {
SpringApplication.run(OrderServiceApplication.class, args);
}
}
也可以指定需要加載的Feign客戶端
@EnableFeignClients(clients = {ProductApi.class})
六、總結
以上就是本文全部內(nèi)容,本文主要為大家介紹了Spring Cloud中實現(xiàn)遠程調(diào)用的另一個組件-OpenFeign的相關知識與操作。感謝各位能夠看到最后,如有問題,歡迎各位大佬在評論區(qū)指正,希望大家可以有所收獲!創(chuàng)作不易,希望大家多多支持。
到此這篇關于Spring Cloud實現(xiàn)遠程調(diào)用OpenFeign組件的方法的文章就介紹到這了,更多相關Spring Cloud調(diào)用OpenFeign內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!
- Spring Cloud OpenFeign實現(xiàn)動態(tài)服務名調(diào)用的示例代碼
- SpringCloudAlibaba微服務調(diào)用組件OpenFeign的方法
- SpringCloud中的OpenFeign調(diào)用解讀
- Spring?Cloud?OpenFeign?遠程調(diào)用
- SpringCloud?OpenFeign?服務調(diào)用傳遞?token的場景分析
- Spring Cloud詳解實現(xiàn)聲明式微服務調(diào)用OpenFeign方法
- SpringCloud學習筆記之OpenFeign進行服務調(diào)用
- Spring Cloud 系列之服務調(diào)用 OpenFeign的實現(xiàn)
- SpringCloud 服務負載均衡和調(diào)用 Ribbon、OpenFeign的方法
相關文章
Java數(shù)據(jù)結構之隊列(動力節(jié)點Java學院整理)
隊列(Queue)是只允許在一端進行插入,而在另一端進行刪除的運算受限的線性表。 這篇文章詳細給大家介紹了java數(shù)據(jù)結構之隊列,感興趣的朋友跟隨小編一起學習吧2017-04-04
java.lang.IllegalStateException異常原因和解決辦法
這篇文章主要給大家介紹了關于java.lang.IllegalStateException異常原因和解決辦法,IllegalStateException是Java標準庫中的一個異常類,通常表示在不合適或無效的情況下執(zhí)行了某個方法或操作,需要的朋友可以參考下2023-07-07
SpringBoot 使用 @Configuration 集中管理 Bean的實
在 SpringBoot 中,@Configuration 注解是專門用來集中管理 Bean 的核心方案,它可以替代傳統(tǒng) XML 配置文件,本文給大家介紹SpringBoot使用@Configuration集中管理 Bean的實戰(zhàn)步驟,感興趣的朋友跟隨小編一起看看吧2026-04-04
在SpringBoot中無縫整合Dubbo的實現(xiàn)過程
微服務架構已經(jīng)成為現(xiàn)代應用開發(fā)的熱門趨勢,而Dubbo作為一款強大的分布式服務框架,與Spring?Boot的結合是構建高性能微服務應用的理想選擇,本文將詳細介紹如何在SpringBoot中無縫整合Dubbo,需要的朋友可以參考下2024-01-01
Java+opencv3.2.0實現(xiàn)人臉檢測功能
這篇文章主要為大家詳細介紹了Java+opencv3.2.0實現(xiàn)人臉檢測功能,具有一定的參考價值,感興趣的小伙伴們可以參考一下2018-02-02

