javascript
SpringCloud 入门教程(六): 用声明式REST客户端Feign调用远端HTTP服务
首先簡(jiǎn)單解釋一下什么是聲明式實(shí)現(xiàn)?
要做一件事, 需要知道三個(gè)要素,where, what, how。即在哪里( where)用什么辦法(how)做什么(what)。什么時(shí)候做(when)我們納入how的范疇。
1)編程式實(shí)現(xiàn): 每一個(gè)要素(where,what,how)都需要用具體代碼實(shí)現(xiàn)來(lái)表示。傳統(tǒng)的方式一般都是編程式實(shí)現(xiàn),業(yè)務(wù)開發(fā)者需要關(guān)心每一處邏輯
2)聲明式實(shí)現(xiàn):?只需要聲明在哪里(where )做什么(what),而無(wú)需關(guān)心如何實(shí)現(xiàn)(how)。Spring的AOP就是一種聲明式實(shí)現(xiàn),比如網(wǎng)站檢查是否登錄,開發(fā)頁(yè)面邏輯的時(shí)候,只需要通過(guò)AOP配置聲明加載頁(yè)面(where)需要做檢查用戶是否登錄(what),而無(wú)需關(guān)心如何檢查用戶是否登錄(how)。如何檢查這個(gè)邏輯由AOP機(jī)制去實(shí)現(xiàn), 而AOP的登錄檢查實(shí)現(xiàn)機(jī)制與正在開發(fā)頁(yè)面的邏輯本身是無(wú)關(guān)的。
在Spring?Cloud Netflix棧中,各個(gè)微服務(wù)都是以HTTP接口的形式暴露自身服務(wù)的,因此在調(diào)用遠(yuǎn)程服務(wù)時(shí)就必須使用HTTP客戶端。Feign就是Spring Cloud提供的一種聲明式REST客戶端。可以通過(guò)Feign訪問調(diào)用遠(yuǎn)端微服務(wù)提供的REST接口。現(xiàn)在我們就用Feign來(lái)調(diào)用SERVICE-HELLOWORLD暴露的REST接口,以獲取到“Hello World”信息。在使用Feign時(shí),Spring Cloud集成了Ribbon和Eureka來(lái)提供HTTP客戶端的負(fù)載均衡。
下面我們就采用Feign的方式來(lái)調(diào)用Hello World服務(wù)集群。
1. 創(chuàng)建Maven工程,加入spring-cloud-starter-feign依賴
<dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-feign</artifactId></dependency>完整的pom文件如下:
?pom.xml
2. 創(chuàng)建啟動(dòng)類,需呀加上@EnableFeignClients注解以使用Feign, 使用@EnableDiscoveryClient開啟服務(wù)自動(dòng)發(fā)現(xiàn)
1 package springcloud.helloworld.feign.service;2 3 import org.springframework.boot.SpringApplication;4 import org.springframework.boot.autoconfigure.SpringBootApplication;5 import org.springframework.cloud.client.discovery.EnableDiscoveryClient;6 import org.springframework.cloud.netflix.feign.EnableFeignClients;7 8 @SpringBootApplication9 @EnableDiscoveryClient 10 @EnableFeignClients 11 public class ServiceFeignApplication { 12 public static void main(String[] args) { 13 SpringApplication.run(ServiceFeignApplication.class, args); 14 } 15 }3. 添加配置文件application.yml, 使用端口8902, 名字定義為service-feign, 并注冊(cè)到eureka服務(wù)中心
1 eureka: 2 client: 3 serviceUrl: 4 defaultZone: http://localhost:8761/eureka/ 5 server: 6 port: 8902 7 spring: 8 application: 9 name: service-feign4.?定義Feign:一個(gè)用@FeignClient注解的接口類,
@FeignClient用于通知Feign組件對(duì)該接口進(jìn)行代理(不需要編寫接口實(shí)現(xiàn)),使用者可直接通過(guò)@Autowired注入; 該接口通過(guò)value定義了需要調(diào)用的SERVICE-HELLOWORLD服務(wù)(通過(guò)服務(wù)中心自動(dòng)發(fā)現(xiàn)機(jī)制會(huì)定位具體URL); @RequestMapping定義了Feign需要訪問的SERVICE-HELLOWORLD服務(wù)的URL(本例中為根“/”)
1 package springcloud.helloworld.feign.service;2 3 import org.springframework.cloud.netflix.feign.FeignClient;4 import org.springframework.web.bind.annotation.RequestMapping;5 import org.springframework.web.bind.annotation.RequestMethod;6 7 @FeignClient(value = "SERVICE-HELLOWORLD")8 public interface HelloWorldService {9 @RequestMapping(value = "/",method = RequestMethod.GET) 10 String sayHello(); 11 }Spring Cloud應(yīng)用在啟動(dòng)時(shí),Feign會(huì)掃描標(biāo)有@FeignClient注解的接口,生成代理,并注冊(cè)到Spring容器中。生成代理時(shí)Feign會(huì)為每個(gè)接口方法創(chuàng)建一個(gè)RequetTemplate對(duì)象,該對(duì)象封裝了HTTP請(qǐng)求需要的全部信息,請(qǐng)求參數(shù)名、請(qǐng)求方法等信息都是在這個(gè)過(guò)程中確定的,Feign的模板化就體現(xiàn)在這里
5. 定義一個(gè)WebController。
注入之前通過(guò)@FeignClient定義生成的bean,?
sayHello()映射到http://localhost:8902/hello, 在這里,我修改了Hello World服務(wù)的映射,將根“/”, 修改成了“/hello”。
1 package springcloud.helloworld.feign.service;2 3 import org.springframework.beans.factory.annotation.Autowired;4 import org.springframework.web.bind.annotation.RequestMapping;5 import org.springframework.web.bind.annotation.RequestMethod;6 import org.springframework.web.bind.annotation.RestController;7 8 @RestController9 public class WebController { 10 @Autowired HelloWorldService helloWorldFeignService; 11 @RequestMapping(value = "/hello",method = RequestMethod.GET) 12 public String sayHello(){ 13 return helloWorldFeignService.sayHello(); 14 } 15 }6. 啟動(dòng)Feign應(yīng)用, 訪問http://localhost:8902/hello, 多次刷新,可以看到和前一章Ribbon里面的應(yīng)用一樣, 兩個(gè)Hello World服務(wù)的輸出交替出現(xiàn)。說(shuō)明通過(guò)Feign訪問服務(wù), Spring Cloud已經(jīng)缺省使用了Ribbon負(fù)載均衡。
? ? ? ? ? ? ? ??
6. 在Feign中使用Apache HTTP Client
Feign在默認(rèn)情況下使用的是JDK原生的URLConnection發(fā)送HTTP請(qǐng)求,沒有連接池,但是對(duì)每個(gè)地址gwai會(huì)保持一個(gè)長(zhǎng)連接,即利用HTTP的persistence connection?。我們可以用Apache的HTTP Client替換Feign原始的http client, 從而獲取連接池、超時(shí)時(shí)間等與性能息息相關(guān)的控制能力。Spring Cloud從Brixtion.SR5版本開始支持這種替換,首先在項(xiàng)目中聲明Apache HTTP Client和feign-httpclient依賴:
1 <!-- 使用Apache HttpClient替換Feign原生httpclient -->2 <dependency>3 <groupId>org.apache.httpcomponents</groupId>4 <artifactId>httpclient</artifactId>5 </dependency>6 <dependency>7 <groupId>com.netflix.feign</groupId>8 <artifactId>feign-httpclient</artifactId>9 <version>${feign-httpclient}</version> 10 </dependency> 然后在application.properties中添加: feign.httpclient.enabled=true?7.?Feign的Encoder、Decoder和ErrorDecoder
Feign將方法簽名中方法參數(shù)對(duì)象序列化為請(qǐng)求參數(shù)放到HTTP請(qǐng)求中的過(guò)程,是由編碼器(Encoder)完成的。同理,將HTTP響應(yīng)數(shù)據(jù)反序列化為Java對(duì)象是由解碼器(Decoder)完成的。默認(rèn)情況下,Feign會(huì)將標(biāo)有@RequestParam注解的參數(shù)轉(zhuǎn)換成字符串添加到URL中,將沒有注解的參數(shù)通過(guò)Jackson轉(zhuǎn)換成json放到請(qǐng)求體中。注意,如果在@RequetMapping中的method將請(qǐng)求方式指定為POST,那么所有未標(biāo)注解的參數(shù)將會(huì)被忽略,例如:
@RequestMapping(value = "/group/{groupId}", method = RequestMethod.GET) void update(@PathVariable("groupId") Integer groupId, @RequestParam("groupName") String groupName, DataObject obj);此時(shí)因?yàn)槁暶鞯氖荊ET請(qǐng)求沒有請(qǐng)求體,所以obj參數(shù)就會(huì)被忽略。
在Spring Cloud環(huán)境下,Feign的Encoder只會(huì)用來(lái)編碼沒有添加注解的參數(shù)。如果你自定義了Encoder, 那么只有在編碼obj參數(shù)時(shí)才會(huì)調(diào)用你的Encoder。對(duì)于Decoder, 默認(rèn)會(huì)委托給SpringMVC中的MappingJackson2HttpMessageConverter類進(jìn)行解碼。只有當(dāng)狀態(tài)碼不在200 ~ 300之間時(shí)ErrorDecoder才會(huì)被調(diào)用。ErrorDecoder的作用是可以根據(jù)HTTP響應(yīng)信息返回一個(gè)異常,該異常可以在調(diào)用Feign接口的地方被捕獲到。我們目前就通過(guò)ErrorDecoder來(lái)使Feign接口拋出業(yè)務(wù)異常以供調(diào)用者處理。
以上6~7完全摘自?http://blog.csdn.net/neosmith/article/details/52449921
總結(jié)
以上是生活随笔為你收集整理的SpringCloud 入门教程(六): 用声明式REST客户端Feign调用远端HTTP服务的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: zcmu1133(dfs+判重)
- 下一篇: ACM-ICPC 2018 徐州赛区网络