第六章 宣告式服務呼叫: Spring Cloud Feign
我們在使用 Spring Cloud Ribbon 時, 通常都會利用它對 RestTemplate 的請求攔截來實現對依賴服務的介面呼叫, 而 RestTemplate 已經實現了對 HTTP 請求的封裝處理, 形成了一套模板化的呼叫方法。在之前的例子中,我們只是簡單介紹了 RestTemplate 呼叫的實現,但是在實際開發中,由於對服務依賴的呼叫可能不止於一處,往往一個介面會被多處呼叫,所以我們通常都會針對各個微服務自行封裝一些客戶端類來包裝這些依賴服務的呼叫。 這個時候我們會發現, 由於 RestTemplate 的封裝, 幾乎每一個呼叫都是簡單的模板化內容。綜合上述這些情況, Spring Cloud Feign 在此基礎上做了進一步封裝, 由它來幫助我們定義和實現依賴服務介面的定義。在 Spring Cloud Feign 的實現下, 我們只需建立一個介面並用註解的方式來配置它, 即可完成對服務提供方的介面繫結, 簡化了在使用 Spring Cloud Ribbon 時自行封裝服務呼叫客戶端的開發量。 Spring Cloud Feign 具備可插拔的註解支援,包括 Feign 註解和 JAX-RS 註解。 同時, 為了適應 Spring 的廣大使用者,它在 Netflix Feign的基礎上擴充套件了對 Spring MVC 的註解支待
快速入門
通過 Spring Cloud Feign 提供的宣告式服務繫結功能來實現對該服務介面的呼叫。首先, 建立一個 Spring Boot 基礎工程, 取名為 feign-consumer, 並在 pom.xml中引入 spring-cloud-starter-eureka和spring-cloud-starter-feign依賴。 具體內容如下所示:
<parent> <groupid>org.springframework.boot</groupid> <artifactid>spring-boot-starter-parent</artifac七Id> <version>l.3.7.RELEASE</version> <relativePath/> <!-- lookup parent from repository --> </parent> <dependencies> <dependency> <groupid>org.springframework.boot</groupid> <artifactid>spring-boot-starter-web</artifactid> </dependency> <dependency> <groupid>org.springfrarnework.cloud</groupid> <artifactid>spring-cloud-starter-eureka</artifactid> </dependency> <dependency> <groupid>org.springframework.cloud</groupid> <artifactid>spring-cloud-starter-feign</artifac七Id> </dependency> </dependencies> <dependencyManagement> <dependencies> <dependency> <groupid>org.springframework.cloud</groupid> <artifactid>spring-cloud-dependencies</artifactid> <version>Brixton.SR5</version> <type>pom</type> <scope>import</scope> </dependency>
</dependencies> </dependencyManagement>
建立應用主類ConsumerApplication, 並通過@EnableFeignClients 註解開啟 Spring Cloud Feign 的支待功能
1 @EnableFeignClients 2 @EnableDiscoveryClient 3 @SpringBootApplication 4 public class ConsumerApplication { 5 publicstatic void main(String(J args) { 6 SpringApplication.run(ConsurnerApplication.class, args); 7 } 8 }
定義 HelloService 介面, 通過@FeignClient 註解指定服務名來繫結服務, 然後再使用 Spring MVC 的註解來繫結具體該服務提供的 REST 介面
1 @FeignClient("hello-service") 2 public interface HelloService { 3 4 @RequestMapping("/hello") 5 String hello(); 6 7 }
注意:這裡服務名不區分大小寫, 所以使用 hello-service和HELLO-SERVICE 都是可以的。 另外, 在 Brixton.SR5 版本中, 原有的 serviceld 屬性已經被廢棄,若要寫屬性名, 可以使用 name或value
接著, 建立一個 ConsumerController 來實現對 Feign 客戶端的呼叫。 使用@Au tow ired 直接注入上面定義的 HelloService 例項, 並在 helloConsumer函式中呼叫這個綁定了 hello-service 服 務介面的客戶端來向該服務發起/hello 介面的呼叫
1 @RestController 2 public class ConsumerController { 3 @Autowired 4 HelloService helloService; 5 @RequestMapping(value = "/feign-consumer", method = RequestMethod.GET) 6 7 public String helloConsumer () { 8 return helloService.hello(); 9 } 10 11 }
最後, 同 Ribbon 實現的服務消費者一樣, 需要在 app巨cation.properties 中指定服務註冊中心, 並定義自身的服務名為 feign-consumer, 為了方便本地除錯與之前的 Ribbon 消費者區分, 埠使用 9001
spring.application.name=feign-consumer server.port=9001 eureka.client.serviceUrl.defaul七Zone=http://localhost:1111/eureka/
啟動服務註冊中心以及兩個HELLO-SERVICE, 然後啟動 FEIGN-CONSUMER,傳送幾次 GET 請求到 http://localhost:9001/feign-consumer, 可以得到如之前Ribbon 實現時 一樣的效果, 正確返回了 "Hello World"。 並且根據控制檯的輸出, 我們可以看到 Feign 實現的消費者,依然是利用 Ribbon 維護了針對 HELLO-SERVICE 的服務列表資訊, 並且通過輪詢實現了客戶端負載均衡。 而與 Ribbon 不同的是, 通過 Feign我們只需定義服務繫結介面, 以宣告式的方法, 優雅而簡單地實現了服務呼叫
引數繫結