一 關(guān)鍵pom
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
< dependencies > < dependency > < groupId >org.springframework.boot</ groupId > < artifactId >spring-boot-starter-web</ artifactId > </ dependency > <!-- Spring Cloud OpenFeign的Starter的依賴 --> < dependency > < groupId >org.springframework.cloud</ groupId > < artifactId >spring-cloud-starter-openfeign</ artifactId > </ dependency > < dependency > < groupId >io.github.openfeign</ groupId > < artifactId >feign-okhttp</ artifactId > </ dependency > </ dependencies > |
二 核心配置
1
2
3
4
5
6
7
8
9
10
11
|
server: port: 8011 spring: application: name: ch4- 3 -okhttp feign: httpclient: enabled: false okhttp: enabled: true |
三 其他代碼位置
https://github.com/cakin24/spring-cloud-code/tree/master/ch4-3/ch4-3-okhttp
四 運(yùn)行測(cè)試
補(bǔ)充:Feign - 獨(dú)立使用 - 替代HttpClient
學(xué)習(xí)項(xiàng)目中,短連接Web服務(wù)器和長(zhǎng)連接IM服務(wù)器之間,是相互配合的。在分布式集群的環(huán)境下,用戶首先通過短連接登錄Web服務(wù)器。Web服務(wù)器在完成用戶的賬號(hào)/密碼驗(yàn)證,返回uid和token時(shí),還需要通過一定策略,獲取目標(biāo)IM服務(wù)器的IP地址和端口號(hào)列表,返回給客戶端。客戶端開始連接IM服務(wù)器,連接成功后,發(fā)送鑒權(quán)請(qǐng)求,鑒權(quán)成功則授權(quán)的長(zhǎng)連接正式建立。
短連接的調(diào)用,使用Feign 技術(shù)。下面是詳解。
看完之后,F(xiàn)eign 獨(dú)立使用,完全可以替換掉目前的Http 客戶端調(diào)用方法。
? 1.1. Feign短連接Restful調(diào)用
一般來說,短連接的服務(wù)接口,都是基于應(yīng)用層Http協(xié)議的Http api 或者RESTful api實(shí)現(xiàn),通過JSON文本格式返回?cái)?shù)據(jù)。如何在Java服務(wù)端調(diào)用其他節(jié)點(diǎn)的Http api 或者RESTful api呢?
至少有以下幾種方式:
(1)JDK原生的URLConnection
(2)Apache的Http Client/HttpComponents
(3)Netty的異步HTTP Client
(4)Spring的RestTemplate
目前用的最多的,基本上是第二種,這也是在單體服務(wù)時(shí)代,最為成熟和穩(wěn)定的方式,也是效率較高的短連接方式。
插入一個(gè)解釋: 什么是RESTful api。REST的全稱是 Representational State Transfer,它是一種API接口的風(fēng)格、也而不是標(biāo)準(zhǔn),只是提供了一組調(diào)用的原則和約束條件。也就是說,在短連接服務(wù)的領(lǐng)域,它算是一種特殊格式的HTTP api。
回到前面的話題,如果同一個(gè)Http api/RESTful api 接口,倘若不止一個(gè)短連接服務(wù)器提供,而是有多個(gè)節(jié)點(diǎn)提供服務(wù),那么,簡(jiǎn)單的使用Http Client調(diào)用,就無能為力了。
Http Client/HttpComponents調(diào)用不能根據(jù)接口的負(fù)載、或者其他的條件,去判斷哪一個(gè)接口應(yīng)該調(diào)用,哪一個(gè)接口不應(yīng)該調(diào)用。解決這個(gè)問題的方式是啥呢?
可以使用Feign來調(diào)用多個(gè)服務(wù)器的同一個(gè)接口。Feign不僅僅可以進(jìn)行同接口多服務(wù)器的負(fù)載均衡,一旦使用了Feign作為http api的客戶端,調(diào)用遠(yuǎn)程的http接口就會(huì)變得像調(diào)用本地方法一樣簡(jiǎn)單。
Feign是何方神圣?它是Netflix開發(fā)的一個(gè)聲明式、模板化的HTTP客戶端, Feign的目標(biāo)是幫助Java工程師更快捷、優(yōu)雅地調(diào)用HTTP API//RESTful api。另外,F(xiàn)eign被無縫集成到了SpringCloud微服務(wù)框架,使用Feign后,可以非常方便項(xiàng)目SpringCloud微服務(wù)技術(shù)。
如果項(xiàng)目使用了SpringCloud技術(shù),那就就可以更加方便的聲明式使用Feign。如果沒有使用SpringCloud,使用Feign也非常之簡(jiǎn)單。Netflix Feign目前改名為OpenFeign,最新版本是2018.5發(fā)布的9.7.0。OpenFeign在Java應(yīng)用中,負(fù)責(zé)處理與遠(yuǎn)程Web服務(wù)的請(qǐng)求響應(yīng),最大限度降低編碼復(fù)雜性。可以說是Java應(yīng)用中調(diào)用Web服務(wù)的客戶端的利器。
下面就看看在單獨(dú)使用Feign的場(chǎng)景下,是怎么調(diào)用遠(yuǎn)程的http服務(wù)。
引入Feign依賴的jar包到pom.xml:
1
2
3
4
5
6
7
8
9
10
|
< dependency > < groupId >io.github.openfeign</ groupId > < artifactId >feign-core</ artifactId > < version >9.7.0</ version > </ dependency > < dependency > < groupId >io.github.openfeign</ groupId > < artifactId >feign-gson</ artifactId > < version >9.7.0</ version > </ dependency > |
接下來,就可以開始使用Feign來調(diào)用遠(yuǎn)程的Http API了。
1.1.1. 短連接API的接口準(zhǔn)備
前面講到,高并發(fā)的IM系統(tǒng)中,用戶的登錄與認(rèn)證、好友的更新與獲取等等一些低頻的請(qǐng)求,這些都使用短連接來實(shí)現(xiàn)。
作為演示,這里僅僅列舉兩個(gè)短連接的API接口:
(1) http://localhost:8080/user/{userid}
這個(gè)接口的功能,是用戶獲取用戶信息,是一個(gè)典型的RESTful類型的接口。{userid}是一個(gè)占位符,調(diào)用的時(shí)候,需要替換成用戶id。 比如說如果用戶id為1,調(diào)用的鏈接為:http://localhost:8080/user/1 。
(2) http://localhost:8080/login/{username}/{password}
這個(gè)接口的功能,用戶登錄的認(rèn)證。占位符{username}是表示用戶名稱,占位符{password}表示用戶密碼。 比如說如果用戶名稱為zhangsan,密碼為123調(diào)用的鏈接為:http://localhost:8080/login/zhangsan/123 。
上面的接口很簡(jiǎn)單,僅僅是為了演示,不能用于生產(chǎn)場(chǎng)景。這些API可以使用Spring MVC 等常見的WEB技術(shù)來實(shí)現(xiàn)。
1.1.2. 申明遠(yuǎn)程接口的本地代理
如何通過Feign技術(shù),來調(diào)用上面的這些Http API呢?
第一步,需要?jiǎng)?chuàng)建一個(gè)本地的API的代理接口。具體如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
|
package com.crazymakercircle.imServer.feignClient; import feign.Param; import feign.RequestLine; public interface UserAction { @RequestLine ( "GET /login/{username}/{password}" ) public String loginAction( @Param ( "username" ) String username, @Param ( "password" ) String password); @RequestLine ( "GET /user/{userid}" ) public String getById( @Param ( "userid" ) Integer userid); } |
在代理接口中,為每一個(gè)遠(yuǎn)程Http API定義一個(gè)方法。
如何將方法對(duì)應(yīng)到遠(yuǎn)程接口呢?
在方法的前面,加上一個(gè)@RequestLine 注解,注明遠(yuǎn)程Http API的請(qǐng)求地址。這個(gè)地址不需要從域名和端口開始,只需要從URI的根目錄“/”開始即可。
比如,如果遠(yuǎn)程Http API的URL為:http://localhost:8080/user/{userid} ,@RequestLine 聲明的值,只需要配成 /user/{userid} 即可。
如何給接口傳遞參數(shù)值呢?
在方法的參數(shù)前面, 加上一個(gè) @Param 注解即可。 @Param內(nèi)容為HTTP鏈接中參數(shù)占位符的名稱。綁定好之后,實(shí)際這個(gè)Java接口中的參數(shù)值,會(huì)替換到@Param注解中的占位符。
比如:由于getById的唯一參數(shù) userid的 @Param注解中,用到的占位符是userid。那么,通過調(diào)用 userAction.getById(100) ,那么userid的值100,就會(huì)用來替換掉請(qǐng)求鏈接http://localhost:8080/user/{userid} 中占位符userid,最終得到的請(qǐng)求鏈接為:http://localhost:8080/user/100。
1.1.3. 遠(yuǎn)程API的本地調(diào)用
在完成遠(yuǎn)程API的本地代理接口的定以后,接下來的工作就是調(diào)用本地代理,這個(gè)工作也是非常的簡(jiǎn)單。
還是以瘋狂創(chuàng)客圈的實(shí)戰(zhàn)項(xiàng)目,獲取用戶信息、和用戶登錄兩個(gè)API的代理接口的調(diào)用為例。
實(shí)戰(zhàn)的代碼如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
|
import com.crazymakercircle.imServer.feignClient.UserAction; import feign.Feign; import feign.Request; import feign.Retryer; import feign.codec.StringDecoder; import org.junit.Test; /** * Created by 尼恩 at 瘋狂創(chuàng)客圈 */ //@ContextConfiguration( // locations = { "classpath:application.properties" }) //@RunWith(SpringJUnit4ClassRunner.class) //@Configuration //自動(dòng)加載配置信息 //@EnableAutoConfiguration public class LoginActionTest { /* // 服務(wù)器ip地址 @Value("${server.web.user.url}") private String userBase;*/ @Test public void testLogin() { UserAction action = Feign.builder() // .decoder(new GsonDecoder()) .decoder( new StringDecoder()) .options( new Request.Options( 1000 , 3500 )) .retryer( new Retryer.Default( 5000 , 5000 , 3 )) .target( UserAction. class , // userBase "http://localhost:8080/" ); String s = action.loginAction( "zhangsan" , "zhangsan" ); System.out.println( "s = " + s); } @Test public void testGetById() { UserAction action = Feign.builder() // .decoder(new GsonDecoder()) .decoder( new StringDecoder()) .target( UserAction. class , "http://localhost:8080/" ); String s = action.getById( 2 ); System.out.println( "s = " + s); } } |
主要的也是最為核心的就一步,構(gòu)建一個(gè)遠(yuǎn)程代理接口的本地實(shí)例。使用Feign.builder() 構(gòu)造器模式方法,帶上一票配置方法的鏈?zhǔn)秸{(diào)用。主要的鏈?zhǔn)秸{(diào)用的配置方法介紹如下:
(1)target 配置方法
為構(gòu)造器配置本地的代理接口,和遠(yuǎn)程的根目錄。代理接口類的每一個(gè)接口方法前@RequestLine 聲明的值,最終都會(huì)加上這個(gè)根目錄。這個(gè)是最為重要的一個(gè)配置方法。代理接口類很重要,最終Feign.builder() 構(gòu)造器返回的本地代理實(shí)例類型,就這個(gè)接口。
(2)options配置方法
options方法指定連接超時(shí)時(shí)長(zhǎng)及響應(yīng)超時(shí)時(shí)長(zhǎng)。
(3)retryer配置方法
retryer方法主要是指定重試策略。
(4)decoder配置方法
decoder方法指定對(duì)象解碼方式,這里用的是基于String字符串的解碼方式。如果需要使用Jackson的解碼方式,需要在pom.xml中添加Jackson的依賴。
主要的配置方法,就介紹這些,具體使用和其他的方法,請(qǐng)參見官網(wǎng)。
通過Feign.builder() 構(gòu)造完成代理實(shí)例后,調(diào)用遠(yuǎn)程API,就變成了調(diào)用Java函數(shù)一樣的簡(jiǎn)單。
建議,如果是獨(dú)立調(diào)用Http服務(wù),盡量使用Feign。
一是簡(jiǎn)單,
二是如果采用httpclient或其他相對(duì)較重的框架,對(duì)初學(xué)者來說編碼量與學(xué)習(xí)曲線都會(huì)是一個(gè)挑戰(zhàn)。
三是,既可以獨(dú)立使用Feign,又可以方便后續(xù)的和Spring Could微服務(wù)框架繼承。
總之,何樂而不為呢?
以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持服務(wù)器之家。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教。
原文鏈接:https://blog.csdn.net/chengqiuming/article/details/102863382