Spring Cloud實(shí)戰(zhàn)小貼士:Feign的繼承特性(偽RPC模式)
通過(guò)之前發(fā)布的《Spring Cloud構(gòu)建微服務(wù)架構(gòu):服務(wù)消費(fèi)者(Feign)》,我們已經(jīng)學(xué)會(huì)如何使用Spring MVC的注解來(lái)綁定服務(wù)接口。我們幾乎完全可以從服務(wù)提供方的Controller中依靠復(fù)制操作,來(lái)構(gòu)建出相應(yīng)的服務(wù)接口客戶端,或是通過(guò)Swagger生成的API文檔來(lái)編寫(xiě)出客戶端,亦或是通過(guò)Swagger的代碼生成器來(lái)生成客戶端綁定。即便如此,有很多的方式來(lái)產(chǎn)生Feign的客戶端程序,依然有很多開(kāi)發(fā)者熱衷于利用公共的依賴接口來(lái)連接服務(wù)提供者和服務(wù)消費(fèi)者的方式。由此,F(xiàn)eign的繼承特性就能很好的派上用處。下面,我們來(lái)詳細(xì)看看如何使用Spring Cloud Feign的繼承特性。
動(dòng)手試一試
接下來(lái)的示例將分為三個(gè)模塊:
- 服務(wù)接口定義模塊:通過(guò)Spring MVC注解定義抽象的interface服務(wù)接口
- 服務(wù)接口實(shí)現(xiàn)模塊:實(shí)現(xiàn)服務(wù)接口定義模塊的interface,該模塊作為服務(wù)提供者注冊(cè)到eureka
- 服務(wù)接口消費(fèi)模塊:服務(wù)接口定義模塊的客戶端實(shí)現(xiàn),該模塊通過(guò)注冊(cè)到eureka來(lái)消費(fèi)服務(wù)接口
服務(wù)接口的定義
- 創(chuàng)建一個(gè)Spring Boot項(xiàng)目:eureka-feign-api,pom.xml的主要內(nèi)容如下:
- <parent>
- <groupId>org.springframework.boot</groupId>
- <artifactId>spring-boot-starter-parent</artifactId>
- <version>1.5.6.RELEASE</version>
- <relativePath/>
- </parent>
- <dependencies>
- <dependency>
- <groupId>org.springframework.boot</groupId>
- <artifactId>spring-boot-starter-web</artifactId>
- </dependency>
- </dependencies>
- <dependencyManagement>
- <dependencies>
- <dependency>
- <groupId>org.springframework.cloud</groupId>
- <artifactId>spring-cloud-dependencies</artifactId>
- <version>Dalston.SR2</version>
- <type>pom</type>
- <scope>import</scope>
- </dependency>
- </dependencies>
- </dependencyManagement>
- 使用Spring MVC注解來(lái)定義服務(wù)接口:
- public interface HelloService {
- @GetMapping("/hello")
- String hello(@RequestParam(value = "name") String name);
- }
- 完成了上述構(gòu)建之后,我們使用mvn install將該模塊構(gòu)建到本地的Maven倉(cāng)庫(kù)中。
服務(wù)接口的實(shí)現(xiàn)
- 創(chuàng)建一個(gè)Spring Boot項(xiàng)目:eureka-feign-client,pom.xml的主要內(nèi)容如下:
- <parent>
- <groupId>org.springframework.boot</groupId>
- <artifactId>spring-boot-starter-parent</artifactId>
- <version>1.5.6.RELEASE</version>
- <relativePath/>
- </parent>
- <dependencies>
- <dependency>
- <groupId>org.springframework.boot</groupId>
- <artifactId>spring-boot-starter-web</artifactId>
- </dependency>
- <dependency>
- <groupId>org.springframework.cloud</groupId>
- <artifactId>spring-cloud-starter-eureka</artifactId>
- </dependency>
- <dependency>
- <groupId>com.didispace</groupId>
- <artifactId>eureka-feign-api</artifactId>
- <version>1.0.0</version>
- </dependency>
- </dependencies>
- <dependencyManagement>
- <dependencies>
- <dependency>
- <groupId>org.springframework.cloud</groupId>
- <artifactId>spring-cloud-dependencies</artifactId>
- <version>Dalston.SR2</version>
- <type>pom</type>
- <scope>import</scope>
- </dependency>
- </dependencies>
- </dependencyManagement>
該模塊需要依賴上面定義的eureka-feign-api,將使用上述定義的HelloService接口來(lái)實(shí)現(xiàn)對(duì)應(yīng)的REST服務(wù)。同時(shí)依賴Eureka是為了將該服務(wù)注冊(cè)到Eureka上供服務(wù)消費(fèi)者發(fā)現(xiàn)。
- 創(chuàng)建應(yīng)用主類。使用@EnableDiscoveryClient注解開(kāi)啟服務(wù)注冊(cè)與發(fā)現(xiàn),并實(shí)現(xiàn)HelloService接口的REST服務(wù):
- @EnableDiscoveryClient
- @SpringBootApplication
- public class Application {
- @RestController
- class HelloController implements HelloService {
- @Override
- public String hello(String name) {
- return "hello " + name;
- }
- }
- public static void main(String[] args) {
- new SpringApplicationBuilder(Application.class).web(true).run(args);
- }
- }
- 編輯application.properties配置內(nèi)容:
- spring.application.name=eureka-feign-client
- server.port=2101
- eureka.client.serviceUrl.defaultZone=http://eureka.didispace.com/eureka/
配置了服務(wù)提供者的名稱eureka-feign-client,服務(wù)提供者的端口號(hào)2101,并將該服務(wù)注冊(cè)到我的公益Eureka注冊(cè)中心上。啟動(dòng)該項(xiàng)目,我們可以通過(guò)訪問(wèn):http://eureka.didispace.com/ ,在該頁(yè)面中找到它。
服務(wù)接口的消費(fèi)
- 創(chuàng)建一個(gè)Spring Boot項(xiàng)目:eureka-feign-consumer,pom.xml的主要內(nèi)容如下:
- <parent>
- <groupId>org.springframework.boot</groupId>
- <artifactId>spring-boot-starter-parent</artifactId>
- <version>1.5.6.RELEASE</version>
- <relativePath/>
- </parent>
- <dependencies>
- <dependency>
- <groupId>org.springframework.boot</groupId>
- <artifactId>spring-boot-starter-web</artifactId>
- </dependency>
- <dependency>
- <groupId>org.springframework.cloud</groupId>
- <artifactId>spring-cloud-starter-eureka</artifactId>
- </dependency>
- <dependency>
- <groupId>org.springframework.cloud</groupId>
- <artifactId>spring-cloud-starter-feign</artifactId>
- </dependency>
- <dependency>
- <groupId>com.didispace</groupId>
- <artifactId>eureka-feign-api</artifactId>
- <version>1.0.0</version>
- </dependency>
- </dependencies>
- <dependencyManagement>
- <dependencies>
- <dependency>
- <groupId>org.springframework.cloud</groupId>
- <artifactId>spring-cloud-dependencies</artifactId>
- <version>Dalston.SR2</version>
- <type>pom</type>
- <scope>import</scope>
- </dependency>
- </dependencies>
- </dependencyManagement>
該模塊較服務(wù)提供者的依賴增加了Feign的依賴,因?yàn)檫@里將使用Feign來(lái)綁定服務(wù)接口的客戶端。下面我們將使用Feign的繼承特性來(lái)輕松的構(gòu)建Feign客戶端。
- 創(chuàng)建應(yīng)用主類。使用@EnableDiscoveryClient注解開(kāi)啟服務(wù)注冊(cè)與發(fā)現(xiàn),并通過(guò)@FeignClient注解來(lái)聲明服務(wù)綁定客戶端:
- @EnableFeignClients
- @EnableDiscoveryClient
- @SpringBootApplication
- public class Application {
- @FeignClient("eureka-feign-client")
- interface HelloServiceClient extends HelloService {
- }
- @RestController
- class TestController {
- @Autowired
- private HelloServiceClient helloServiceClient;
- @GetMapping("/test")
- public String test(String name) {
- return helloServiceClient.hello(name);
- }
- }
- public static void main(String[] args) {
- new SpringApplicationBuilder(Application.class).web(true).run(args);
- }
- }
從上述代碼中我們可以看到,利用Feign的繼承特性,@FeignClient注解只需要通過(guò)聲明一個(gè)接口來(lái)繼承在API模塊中定義的公共interface就能產(chǎn)生服務(wù)接口的Feign客戶端了。而@FeignClient中的值需要填寫(xiě)該服務(wù)的具體服務(wù)名(服務(wù)提供者的spring.application.name配置值)。
- 編輯服務(wù)消費(fèi)者的application.properties配置內(nèi)容,將服務(wù)消費(fèi)者注冊(cè)到eureka上來(lái)消費(fèi)服務(wù):
- spring.application.name=eureka-feign-consumer
- server.port=2102
- eureka.client.serviceUrl.defaultZone=http://eureka.didispace.com/eureka/
- 啟動(dòng)eureka-feign-consumer之后,我們可以通過(guò)訪問(wèn):http://localhost:2102/test ,來(lái)實(shí)驗(yàn)eureka-feign-consumer對(duì)eureka-feign-client接口的調(diào)用。
本文示例
程序清單:
- eureka-feign-api:服務(wù)接口定義
- eureka-feign-client:服務(wù)接口實(shí)現(xiàn)的提供方
- eureka-feign-consumer:服務(wù)接口的調(diào)用方
【本文為51CTO專欄作者“翟永超”的原創(chuàng)稿件,轉(zhuǎn)載請(qǐng)通過(guò)51CTO聯(lián)系作者獲取授權(quán)】