Spring中OpenFeign的使用方法最佳實(shí)踐
1. RestTemplate存在的問題
觀察我們之前遠(yuǎn)程調(diào)用的代碼
public OrderInfo selectOrder(Integer id){ OrderInfo orderInfo = orderMapper.selectOrderById(id); //把獲取到的服務(wù)URL拼接到遠(yuǎn)程調(diào)用的URL中 String url = "http://product-service/product/select?id=" + orderInfo.getProductId(); ProductInfo productInfo = restTemplate.getForObject(url, ProductInfo.class); orderInfo.setProductInfo(productInfo); return orderInfo; }
雖然說RestTemplate對HTTP封裝之后,已經(jīng)比直接使用HTTP Client方便很多,但是還是存在一些問題的.
- 需要拼接URL,靈活性高,但是封裝臃腫,URL復(fù)雜的時候,容易出錯.
- 代碼可讀性差,風(fēng)格不統(tǒng)一.
微服務(wù)之間的通行主要有兩種方式,一種是RPC,一種是HTTP.在SpringCloud中,默認(rèn)是使用HTTP進(jìn)行通信的,最常用的實(shí)現(xiàn)形式有兩種:
- RestTemplate
- OpenFeign
接下來我們就來詳細(xì)介紹一下OpenFeign.
2. OpenFeign介紹
OpenFeign是一個聲明式的Web Service客戶端.它讓微服務(wù)之間的調(diào)用變得更加簡單,類似與Controller調(diào)用Service,只需要創(chuàng)建一個接口,然后再添加注解就可以使用OpenFeign.
2.1 引入依賴
首先我們需要在服務(wù)調(diào)用方(order-service)中引入依賴
<dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-openfeign</artifactId> </dependency>
2.2 添加注解
在order-service的啟動類添加注解,@EnableFeignClients
,開啟OpenFeign的功能.
@SpringBootApplication @EnableFeignClients public class OrderServiceApplication { public static void main(String[] args) { SpringApplication.run(OrderServiceApplication.class,args); } }
2.3 編寫OpenFeign客戶端
在調(diào)用其他服務(wù)的客戶端之下,編寫API調(diào)用接口,基于SpringMVC的注解來聲明遠(yuǎn)程調(diào)用的信息.
@FeignClient(name = "product-service") public interface ProductApi { @RequestMapping("/product/select") ProductInfo getProductInfo(@RequestParam("id")Integer id); }
[注意]:在接口的參數(shù)前面必須使用@RequestParam加上所調(diào)用服務(wù)接口的對應(yīng)參數(shù),否則參數(shù)無法傳入,就相當(dāng)于在請求的后面加上了?參數(shù)=xxx
.
也可以把該服務(wù)的接口的統(tǒng)一前綴(放在類上的@RequestMapping
)統(tǒng)一放到FeignClient注解的Path參數(shù)中.
@FeignClient(name = "product-service",path = "/product") public interface ProductApi { @RequestMapping("/select") ProductInfo getProductInfo(@RequestParam("id")Integer id); }
@FeignClient
注解作用在接口上,參數(shù)說明:
- name/value: 指定OpenFeign的名稱,也就是被調(diào)用的微服務(wù)的名稱,用于服務(wù)發(fā)現(xiàn),Feign底層會使用SpringLoadBalance進(jìn)行負(fù)載均衡.
當(dāng)然也可以使用URL屬性指定一個具體的URL. - Path: 定義當(dāng)前FeignClient的統(tǒng)一前綴,一般是被調(diào)用方Controller層的類注解.
2.4 遠(yuǎn)程調(diào)用
修改遠(yuǎn)程調(diào)用方法
@Service public class OrderService { @Autowired private OrderMapper orderMapper; @Autowired private ProductApi api; //設(shè)置原子類 public OrderInfo selectOrder(Integer id){ OrderInfo orderInfo = orderMapper.selectOrderById(id); //把獲取到的服務(wù)URL拼接到遠(yuǎn)程調(diào)用的URL中 Integer productId = orderInfo.getProductId(); ProductInfo productInfo = api.getProductInfo(productId); orderInfo.setProductInfo(productInfo); return orderInfo; } }
2.5 測試
啟動服務(wù).訪問接口,測試遠(yuǎn)程調(diào)用.
3. OpenFeign參數(shù)傳遞
3.1 傳遞單個參數(shù)
我們上面2.4的例子就是單個參數(shù)的調(diào)用.下面我們再來舉一個例子
- 服務(wù)提供方product-service
@RestController @RequestMapping("/product") public class ProductController { @RequestMapping("/p1") public String p1(Integer id){ return "接收到參數(shù)"+id; } }
- FeginClient
@FeignClient(value = "product-service") public interface ProductApi { @RequestMapping("/product/p1") String p1(@RequestParam("id") Integer id); }
和我們上面提到的一樣,@RequestParam是用來做參數(shù)綁定的,不能省略.
3. order-service
@RequestMapping("/order") @RestController public class OrderController { @Autowired private ProductApi api; @RequestMapping("/p1") public String p1(Integer id){ return api.p1(id); } }
遠(yuǎn)程測試調(diào)用:GET http://127.0.0.1:8080/order/p1?id=1
3.2 傳遞多個參數(shù)
使用多個@RequestParam
進(jìn)行參數(shù)綁定即可
- 服務(wù)提供方product-service
@RestController @RequestMapping("/product") public class ProductController { @RequestMapping("/p2") public String p2(Integer id1,Integer id2){ return "接收到參數(shù)1:" + id1 + ",接收到參數(shù)2:" + id2; } }
- FeignClient
@FeignClient(value = "product-service") public interface ProductApi { @RequestMapping("/product/p2") String p2(@RequestParam("id1") Integer p1,@RequestParam("id2") Integer p2); }
- 服務(wù)消費(fèi)方order-service
@RequestMapping("/order") @RestController public class OrderController { @Autowired private ProductApi api; @RequestMapping("/p2") public String p2(Integer p1,Integer p2){ return api.p2(p1,p2); } }
調(diào)用接口進(jìn)行測試:GET http://127.0.0.1:8080/order/p2?p1=1&p2=2
4.3 傳遞對象
- 服務(wù)提供方product-service
@RequestMapping("/p3") public String p3(ProductInfo productInfo){ return "接收到對象:" + productInfo; }
- Feign
@RequestMapping("/product/p3") String p3(@SpringQueryMap ProductInfo productInfo);
其中@SpringQueryMap
注解表示的是:可以方便地將一個對象的屬性作為請求的查詢參數(shù)添加到請求的 URL中,避免了手動構(gòu)建查詢參數(shù)字符串(如json)的繁瑣過程.
3. order-service
@RequestMapping("/p3") public String p3(ProductInfo productInfo){ return api.p3(productInfo); }
測試遠(yuǎn)程調(diào)用:GET http://127.0.0.1:8080/order/p3?id=5&productName=zhangsan
3.4 傳遞Json
和我們之前學(xué)習(xí)SpringBoot的時候一樣,同樣是使用@RequestBody
注解進(jìn)行綁定.
注意由于數(shù)據(jù)在服務(wù)之間一直是按照J(rèn)son格式傳遞的,所以服務(wù)方,服務(wù)調(diào)用方,FeignClient的參數(shù)上都需要加上注解.
- 服務(wù)提供方product-service
@RequestMapping("/p4") public String p4(@RequestBody ProductInfo productInfo){ return "接收到對象:" + productInfo; }
- FeignClient
@RequestMapping("/product/p4") String p4(@RequestBody ProductInfo productInfo);
- 服務(wù)消費(fèi)方order-service
@RequestMapping("/p4") public String p4(@RequestBody ProductInfo productInfo){ return api.p4(productInfo); }
測試遠(yuǎn)程調(diào)用:http://127.0.0.1:8080/order/p4
4. 最佳實(shí)踐
通過觀察,我們也能看出來,Feign的客戶端與服務(wù)提供者的controller代碼非常相似.
Feign客戶端:
@FeignClient(value = "product-service") public interface ProductApi { @RequestMapping("/product/p1") String p1(@RequestParam("id") Integer id); }
服務(wù)提供方Controller
@RestController @RequestMapping("/product") public class ProductController { @RequestMapping("/p1") public String p1(Integer id){ return "接收到參數(shù)"+id; } }
有沒有一種方法可以簡化這種寫法呢?
4.1 Feign繼承方式
Feign支持繼承的方式,我們可以把一些常見的操作封裝到接口里.
我可以定義好一個接口,服務(wù)提供方實(shí)現(xiàn)這個接口,服務(wù)消費(fèi)方編寫Feign接口的時候,直接繼承這個接口.
接口可以放在一個公共的jar包中,供服務(wù)提供方和服務(wù)消費(fèi)方使用.
- 新建一個模塊
- 引入依賴
<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>
- 編寫接口
復(fù)制ProductInfo類和ProductApi到product-api模塊中.把ProductApi改名為ProductInterface - 打jar包,并安裝到本地Maven倉庫
點(diǎn)擊install.該模塊就會被安裝到本地的Maven倉庫.
由于jar包中已經(jīng)有了ProductInfo類,所以我們就可以把product-service和order-service的ProductInfo類注掉了. - 服務(wù)提供方
需要先在服務(wù)方中引入對應(yīng)模塊的依賴.
<dependency> <groupId>org.example</groupId> <artifactId>product-api</artifactId> <version>1.0-SNAPSHOT</version> <scope>compile</scope> </dependency>
服務(wù)方product-service
直接實(shí)現(xiàn)接口ProductInterface
.
@RestController @RequestMapping("/product") public class ProductController implements ProductInterface { @Autowired private ProductService productService; @RequestMapping("/select") public ProductInfo getProductInfo(Integer id){ return productService.selectById(id); } @RequestMapping("/p1") public String p1(Integer id){ return "接收到參數(shù)"+id; } @RequestMapping("/p2") public String p2(Integer id1,Integer id2){ return "接收到參數(shù)1:" + id1 + ",接收到參數(shù)2:" + id2; } @RequestMapping("/p3") public String p3(ProductInfo productInfo){ return "接收到對象:" + productInfo; } @RequestMapping("/p4") public String p4(@RequestBody ProductInfo productInfo){ return "接收到對象:" + productInfo; } }
- 服務(wù)消費(fèi)方
同樣,首先先添加依賴.
之后讓FeignClient繼承ProductInterface
@FeignClient(value = "product-service") public interface ProductApi extends ProductInterface { }
注意在上述步驟中,把ProductInfo類引入包的路徑全部改為之前打包的product-api模塊下ProductInfo類的路徑.
- 測試接口
http://127.0.0.1:8080/order/select?id=1
4.2 Feign抽取方式
官方推薦Feign的使用方式為繼承的方式,但是企業(yè)開發(fā)中,更多是把Feign接口抽取為?個獨(dú)立的模塊(做法和繼承相似,但理念不同).
操作方法:
將Feign的Client抽取為?個獨(dú)立的模塊,并把涉及到的實(shí)體類等都放在這個模塊中,打成?個Jar.服務(wù)消費(fèi)方只需要依賴該Jar包即可.這種方式在企業(yè)中比較常見,Jar包通常由服務(wù)提供方來實(shí)現(xiàn).
前4步和前面繼承的方式一樣.只不過接口ProductApi在復(fù)制到新模塊的時候不用修改名字
- 服務(wù)消費(fèi)方使用product-api
首先引入依賴,之后把該模塊中原有的ProductApi接口注掉.
<dependency> <groupId>org.example</groupId> <artifactId>product-api</artifactId> <version>1.0-SNAPSHOT</version> </dependency>
之后指定掃描類
在啟動類中添加需要加載的Feign客戶端.
@SpringBootApplication @EnableFeignClients(clients = ProductApi.class) public class OrderServiceApplication { public static void main(String[] args) { SpringApplication.run(OrderServiceApplication.class,args); } }
- 測試
遠(yuǎn)程調(diào)用接口http://127.0.0.1:8080/order/select?id=1
總結(jié)
到此這篇關(guān)于Spring中OpenFeign的使用方法的文章就介紹到這了,更多相關(guān)Spring OpenFeign的使用內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
JDK13.0.1安裝與環(huán)境變量的配置教程圖文詳解(Win10平臺為例)
這篇文章主要介紹了JDK13.0.1安裝與環(huán)境變量的配置教程圖文詳解(Win10平臺為例),本文圖文并茂給大家介紹的非常詳細(xì),具有一定的參考借鑒價值,需要的朋友可以參考下2020-01-01使用@DS輕松解決動態(tài)數(shù)據(jù)源的問題
這篇文章主要介紹了使用@DS輕松解決動態(tài)數(shù)據(jù)源的問題,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2022-05-05java 讀取excel文件轉(zhuǎn)換成json格式的實(shí)例代碼
這篇文章主要介紹了 java 讀取excel文件轉(zhuǎn)換成json格式的實(shí)例代碼,需要的朋友可以參考下2018-04-04