SpringCloud OpenFeign + Nacos正確打開方式!

作者 | 磊哥
來(lái)源 | Java中文社群(ID:javacn666)
轉(zhuǎn)載請(qǐng)聯(lián)系授權(quán)(微信ID:GG_Stone)
Nacos 支持兩種 HTTP 服務(wù)請(qǐng)求,一個(gè)是 REST Template,另一個(gè)是 Feign Client。之前的文章咱們介紹過 Rest Template 的調(diào)用方式,主要是通過 Ribbon(負(fù)載均衡) + RestTemplate 實(shí)現(xiàn) HTTP 服務(wù)調(diào)用的,請(qǐng)求的核心代碼是這樣的:
@RestController
public?class?ConsumerController?{
????@Resource
????private?RestTemplate?restTemplate;
????@GetMapping("/consumer")
????public?String?consumer(@RequestParam?String?name)?{
????????//?請(qǐng)求并獲取結(jié)果(springcloud-nacos-provider?是?nacos?中的服務(wù)id)
????????String?result?=?restTemplate.getForObject("http://springcloud-nacos-provider/call/"?+?name,?String.class);
????????return?result;
????}
}
從上述的實(shí)現(xiàn)代碼我們可以看出一個(gè)問題,雖然以上代碼可以實(shí)現(xiàn) HTTP 服務(wù)調(diào)用,但需要開發(fā)者手動(dòng)拼接調(diào)用地址和參數(shù),并且遠(yuǎn)程服務(wù)調(diào)用和客戶端自身的業(yè)務(wù)邏輯實(shí)現(xiàn)是混合在一起,不利于后期的維護(hù)與擴(kuò)展,那如何要解決這個(gè)問題呢?這就是我們今天要介紹的 OpenFeign 的原因了。
OpenFeign 介紹
OpenFeign 的全稱是 Spring Cloud OpenFeign,它是 Spring 官方推出的一種聲明式服務(wù)調(diào)用和負(fù)載均衡組件。它的出現(xiàn)就是為了替代已經(jīng)進(jìn)入停更維護(hù)狀態(tài)的 Feign(Netflix Feign)的。也就是說(shuō) OpenFeign(Spring Cloud OpenFeign)是 Feign 的升級(jí)版,它們的關(guān)系如下圖所示:
因?yàn)?Feign 停更維護(hù)了,所以 Spring 官方需要推出了一個(gè)新的新的框架來(lái)對(duì) Feign 功能進(jìn)行升級(jí)和擴(kuò)展。
OpenFeign 常用注解
OpenFeign 聲明式服務(wù)調(diào)用和負(fù)載均衡組件,因此它的核心是使用注解 + 接口的方式實(shí)現(xiàn)服務(wù)調(diào)用,所以了解 OpenFeign 的注解就至關(guān)重要了。對(duì)于 Feign 框架來(lái)說(shuō),它只支持 Feign 注解和 JAX-RS 注解,但 OpenFeign 在 Feign 的基礎(chǔ)上還增加了對(duì) Spring MVC 注解的支持,例如 @RequestMapping、@GetMapping 和 @PostMapping 等注解。OpenFeign 常用注解有以下幾個(gè):
- @EnableFeignClients:該注解用于開啟 OpenFeign 功能,當(dāng) Spring Cloud 應(yīng)用啟動(dòng)時(shí),OpenFeign 會(huì)掃描標(biāo)有 @FeignClient 注解的接口,生成代理并注冊(cè)到 Spring 容器中。
- @FeignClient:該注解用于通知 OpenFeign 組件對(duì) @RequestMapping 注解下的接口進(jìn)行解析,并通過動(dòng)態(tài)代理的方式產(chǎn)生實(shí)現(xiàn)類,實(shí)現(xiàn)負(fù)載均衡和服務(wù)調(diào)用。
- @RequestMapping:向服務(wù)提供者發(fā)起 Request 請(qǐng)求(默認(rèn)為 GET 方式請(qǐng)求),這里需要注意 @RequestMapping/@GetMapping/@PostMapping 和 Spring MVC 中的同名注解的含義是完全不同的。
- @GetMapping:向服務(wù)提供者發(fā)起 GET 請(qǐng)求。
- @PostMapping:向服務(wù)提供者發(fā)起 POST 請(qǐng)求。
OpenFeign 使用
OpenFeign 是用在服務(wù)消費(fèi)端的,有消費(fèi)端就得有服務(wù)提供端,它們的關(guān)系如下圖所示:
所以我們先要?jiǎng)?chuàng)建一個(gè)服務(wù)提供者 Provider,創(chuàng)建步驟如下。
創(chuàng)建服務(wù)提供者
第一步:先創(chuàng)建一個(gè) Spring Boot 項(xiàng)目(Spring Cloud 項(xiàng)目是基于 Spring Boot 創(chuàng)建的),添加 spring-web 和 nacos-discovery 依賴,具體依賴信息如下:
<dependency>
??<groupId>org.springframework.bootgroupId>
??<artifactId>spring-boot-starter-webartifactId>
dependency>
<dependency>
??<groupId>com.alibaba.cloudgroupId>
??<artifactId>spring-cloud-starter-alibaba-nacos-discoveryartifactId>
dependency>
第二步:設(shè)置 Nacos 相關(guān)配置,在 application.yml 中添加以下配置:
spring:
??application:
????name:?springcloud-nacos-provider?#?項(xiàng)目名稱(nacos?注冊(cè)的服務(wù)名)
??cloud:
????nacos:
??????discovery:
????????username:?nacos?#?nacos?登錄用戶名
????????password:?nacos666?#?nacos?密碼
????????server-addr:?127.0.0.1:8848?#?nacos?服務(wù)端地址
server:
??port:?8081?#?項(xiàng)目啟動(dòng)端口號(hào)
第三步:添加服務(wù)方法,如下代碼所示:
import?org.springframework.boot.SpringApplication;
import?org.springframework.boot.autoconfigure.SpringBootApplication;
import?org.springframework.web.bind.annotation.PathVariable;
import?org.springframework.web.bind.annotation.RequestMapping;
import?org.springframework.web.bind.annotation.RestController;
@SpringBootApplication
@RestController
public?class?HttpProviderApplication?{
????public?static?void?main(String[]?args)?{
????????SpringApplication.run(HttpProviderApplication.class,?args);
????}
????/**
?????*?為客戶端提供可調(diào)用的接口
?????*/
????@RequestMapping("/call/{name}")
????public?String?call(@PathVariable?String?name)?{
????????return?LocalTime.now()?+?"——服務(wù)提供者1:"?+?name;
????}
}
創(chuàng)建服務(wù)消費(fèi)者
第一步:創(chuàng)建一個(gè) Spring Boot 項(xiàng)目,添加 spring-web、nacos-discovery 和 openfeign 依賴,具體依賴內(nèi)容如下:
<dependency>
????<groupId>org.springframework.bootgroupId>
????<artifactId>spring-boot-starter-webartifactId>
dependency>
<dependency>
????<groupId>com.alibaba.cloudgroupId>
????<artifactId>spring-cloud-starter-alibaba-nacos-discoveryartifactId>
dependency>
<dependency>
????<groupId>org.springframework.cloudgroupId>
????<artifactId>spring-cloud-starter-openfeignartifactId>
dependency>
第二步:設(shè)置 Nacos 相關(guān)配置,在 application.yml 中添加以下配置:
spring:
??application:
????name:?springcloud-nacos-consumer?#?項(xiàng)目名稱(nacos?注冊(cè)的服務(wù)名)
??cloud:
????nacos:
??????discovery:
????????username:?nacos?#?nacos?登錄用戶名
????????password:?nacos666?#?nacos?密碼
????????server-addr:?127.0.0.1:8848?#?nacos?服務(wù)端地址
server:
??port:?8093?#?項(xiàng)目啟動(dòng)端口號(hào)
第三步:在 Spring Boot 項(xiàng)目的啟動(dòng)文件上添加 @EnableFeignClients 注解,開啟 OpenFeign,具體實(shí)現(xiàn)代碼如下:
import?org.springframework.boot.SpringApplication;
import?org.springframework.boot.autoconfigure.SpringBootApplication;
import?org.springframework.cloud.openfeign.EnableFeignClients;
@SpringBootApplication
@EnableFeignClients?//?啟用?OpenFeign
public?class?OpenfeignConsumerApplication?{
????public?static?void?main(String[]?args)?{
????????SpringApplication.run(OpenfeignConsumerApplication.class,?args);
????}
}
第四步:最重要的一步,創(chuàng)建 OpenFeign 與服務(wù)提供者的調(diào)用接口,實(shí)現(xiàn)代碼如下:
import?org.springframework.cloud.openfeign.FeignClient;
import?org.springframework.web.bind.annotation.GetMapping;
import?org.springframework.web.bind.annotation.PathVariable;
@FeignClient("springcloud-nacos-provider")?//?nacos?服務(wù)?id
public?interface?SpringCloudNacosProviderClient?{
????@GetMapping("/call/{name}")?//?使用?get?方式,調(diào)用服務(wù)提供者的?/call/{name}?接口
????public?String?call(@PathVariable(value?=?"name")?String?name);
}
第五步:編寫服務(wù)調(diào)用者代碼,經(jīng)過了上一步對(duì)服務(wù)提供者的封裝之后,在控制器中我們可以像調(diào)用本地方法一樣調(diào)用遠(yuǎn)程接口了,具體實(shí)現(xiàn)代碼如下:
import?com.example.openfeignconsumer.feignclient.SpringCloudNacosProviderClient;
import?org.springframework.web.bind.annotation.GetMapping;
import?org.springframework.web.bind.annotation.RequestParam;
import?org.springframework.web.bind.annotation.RestController;
import?javax.annotation.Resource;
@RestController
public?class?ConsumerController?{
????@Resource
????private?SpringCloudNacosProviderClient?providerClient;?//?加載?openfeign?client
????
????@GetMapping("/consumer")
????public?String?consumer(@RequestParam?String?name)?{
????????//?向調(diào)用本地方法一樣,調(diào)用?openfeign?client?中的方法
????????return?providerClient.call(name);
????}
}
然后分別啟動(dòng)服務(wù)提供者和服務(wù)調(diào)用者程序,執(zhí)行結(jié)果如下圖所示:
注意事項(xiàng)
OpenFeign 默認(rèn)的接口超時(shí)時(shí)間為 1s,所以如果接口的執(zhí)行時(shí)間超過 1s,那么程序調(diào)用就會(huì)報(bào)錯(cuò)。接下來(lái),我們編寫程序測(cè)試一下,將服務(wù)提供者的代碼休眠 2s,具體實(shí)現(xiàn)代碼如下:
import?org.springframework.boot.SpringApplication;
import?org.springframework.boot.autoconfigure.SpringBootApplication;
import?org.springframework.web.bind.annotation.PathVariable;
import?org.springframework.web.bind.annotation.RequestMapping;
import?org.springframework.web.bind.annotation.RestController;
import?java.time.LocalTime;
import?java.util.concurrent.TimeUnit;
@SpringBootApplication
@RestController
public?class?HttpProviderApplication?{
????public?static?void?main(String[]?args)?{
????????SpringApplication.run(HttpProviderApplication.class,?args);
????}
????/**
?????*?為客戶端提供可調(diào)用的接口
?????*/
????@RequestMapping("/call/{name}")
????public?String?call(@PathVariable?String?name)?throws?InterruptedException?{
????????//?讓程序休眠?2s
????????TimeUnit.SECONDS.sleep(2);
????????return?LocalTime.now()?+?"——服務(wù)提供者1:"?+?name;
????}
}
之后使用 OpenFeign 客戶端訪問服務(wù),就會(huì)出現(xiàn)如下報(bào)錯(cuò)信息:
解決方案:通過修改配置文件中的超時(shí)時(shí)長(zhǎng),也就是手動(dòng)調(diào)節(jié)接口的超時(shí)時(shí)長(zhǎng)來(lái)解決此問題,因?yàn)?1s 確實(shí)太短了,修改的配置信息如下:
ribbon:
??ReadTimeout:?5000?#?請(qǐng)求連接的超時(shí)時(shí)間
??ConnectionTimeout:?10000?#?請(qǐng)求處理的超時(shí)時(shí)間
總結(jié)
OpenFeign 是基于 Feign 實(shí)現(xiàn)的,是 Spring Cloud 官方提供的注解式調(diào)用 REST 接口框架,OpenFeign/Feign 底層是基于 Ribbon 實(shí)現(xiàn)負(fù)載均衡的。使用 OpenFeign 有三個(gè)關(guān)鍵步驟,首先在 Spring Boot 啟動(dòng)類上使用注解 @EnableFeignClients 開啟 OpenFeign;第二,使用 @FeignClient + @GetMapping/@PostMapping 調(diào)用服務(wù)提供者的接口;第三,在客戶端中注入 Feign Client 對(duì)象,像調(diào)用本地方法一樣調(diào)用遠(yuǎn)程接口。
項(xiàng)目源碼
https://gitee.com/mydb/spring-cloud-alibaba-example
參考 & 鳴謝
c.biancheng.net/springcloud/open-feign.html
是非審之于己,毀譽(yù)聽之于人,得失安之于數(shù)。
公眾號(hào):Java中文社群
Java面試合集:https://gitee.com/mydb/interview

往期推薦

SpringCloud Ribbon中的7種負(fù)載均衡策略!

SpringCloud Nacos + Ribbon 調(diào)用服務(wù)的 2 種方法!

Spring Cloud Alibaba Nacos 的 2 種健康檢查機(jī)制!

