瘋狂創客圈,一個Java 高併發研習社羣 【博客園 總入口 】html
瘋狂創客圈,傾力推出: 《Netty Zookeeper Redis 高併發實戰》一書, 面試必備 + 面試必備 + 面試必備git
你們好,我是做者尼恩。目前和幾個小夥伴一塊兒,組織了一個高併發的實戰社羣【瘋狂創客圈】。正在開始高併發、億級流程的 IM 聊天程序 學習和實戰github
順便說明下:
本文的內容只是一個初稿、初稿,本文的知識,在《Netty Zookeeper Redis 高併發實戰》一書時,進行大篇幅的完善和更新,而且進行的源碼的升級。 博客和書不同,書的內容更加系統化、全面化,更加層層升入、井井有條、更屢次的錯誤排查,請你們以書的內容爲準。
本文的最終內容, 具體請參考瘋狂創客圈 傾力編著,機械工業出版社出版的 《Netty Zookeeper Redis 高併發實戰》一書 。
web
在瘋狂創客圈的 億級流程的 IM 聊天程序 學習項目中,短鏈接Web服務器和長鏈接IM服務器之間,是相互配合的。在分佈式集羣的環境下,用戶首先經過短鏈接登陸Web服務器。Web服務器在完成用戶的帳號/密碼驗證,返回uid和token時,還須要經過必定策略,獲取目標IM服務器的IP地址和端口號列表,返回給客戶端。客戶端開始鏈接IM服務器,鏈接成功後,發送鑑權請求,鑑權成功則受權的長鏈接正式創建。面試
短鏈接的調用,使用Feign 技術。下面是詳解。api
看完以後,Feign 獨立使用,徹底能夠替換掉目前的Http 客戶端調用方法。服務器
1.1. Feign短鏈接Restful調用併發
通常來講,短鏈接的服務接口,都是基於應用層Http協議的Http api 或者RESTful api實現,經過JSON文本格式返回數據。如何在Java服務端調用其餘節點的Http api 或者RESTful api呢?app
至少有如下幾種方式:負載均衡
(1)JDK原生的URLConnection
(2)Apache的Http Client/HttpComponents
(3)Netty的異步HTTP Client
(4)Spring的RestTemplate
目前用的最多的,基本上是第二種,這也是在單體服務時代,最爲成熟和穩定的方式,也是效率較高的短鏈接方式。
插入一個解釋: 什麼是RESTful api。REST的全稱是 Representational State Transfer,它是一種API接口的風格、也而不是標準,只是提供了一組調用的原則和約束條件。也就是說,在短鏈接服務的領域,它算是一種特殊格式的HTTP api。
回到前面的話題,若是同一個Http api/RESTful api 接口,假若不止一個短鏈接服務器提供,而是有多個節點提供服務,那麼,簡單的使用Http Client調用,就無能爲力了。
Http Client/HttpComponents調用不能根據接口的負載、或者其餘的條件,去判斷哪個接口應該調用,哪個接口不該該調用。解決這個問題的方式是啥呢?
可使用Feign來調用多個服務器的同一個接口。Feign不只僅能夠進行同接口多服務器的負載均衡,一旦使用了Feign做爲http api的客戶端,調用遠程的http接口就會變得像調用本地方法同樣簡單。
Feign是何方神聖?它是Netflix開發的一個聲明式、模板化的HTTP客戶端, Feign的目標是幫助Java工程師更快捷、優雅地調用HTTP API//RESTful api。另外,Feign被無縫集成到了SpringCloud微服務框架,使用Feign後,能夠很是方便項目SpringCloud微服務技術。
若是項目使用了SpringCloud技術,那就就能夠更加方便的聲明式使用Feign。若是沒有使用SpringCloud,使用Feign也很是之簡單。Netflix Feign目前更名爲OpenFeign,最新版本是2018.5發佈的9.7.0。OpenFeign在Java應用中,負責處理與遠程Web服務的請求響應,最大限度下降編碼複雜性。能夠說是Java應用中調用Web服務的客戶端的利器。
下面就看看在單獨使用Feign的場景下,是怎麼調用遠程的http服務。
引入Feign依賴的jar包到pom.xml:
<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來調用遠程的Http API了。
前面講到,高併發的IM系統中,用戶的登陸與認證、好友的更新與獲取等等一些低頻的請求,這些都使用短鏈接來實現。
做爲演示,這裏僅僅列舉兩個短鏈接的API接口:
(1) http://localhost:8080/user/{userid}
這個接口的功能,是用戶獲取用戶信息,是一個典型的RESTful類型的接口。{userid}是一個佔位符,調用的時候,須要替換成用戶id。 好比說若是用戶id爲1,調用的連接爲:http://localhost:8080/user/1 。
(2) http://localhost:8080/login/{username}/{password}
這個接口的功能,用戶登陸的認證。佔位符{username}是表示用戶名稱,佔位符{password}表示用戶密碼。 好比說若是用戶名稱爲zhangsan,密碼爲123調用的連接爲:http://localhost:8080/login/zhangsan/123 。
上面的接口很簡單,僅僅是爲了演示,不能用於生產場景。這些API可使用Spring MVC 等常見的WEB技術來實現。
如何經過Feign技術,來調用上面的這些Http API呢?
第一步,須要建立一個本地的API的代理接口。具體以下:
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); }
在代理接口中,爲每個遠程Http API定義一個方法。
如何將方法對應到遠程接口呢?
在方法的前面,加上一個@RequestLine 註解,註明遠程Http API的請求地址。這個地址不須要從域名和端口開始,只須要從URI的根目錄「/」開始便可。
好比,若是遠程Http API的URL爲:http://localhost:8080/user/{userid} ,@RequestLine 聲明的值,只須要配成 /user/{userid} 便可。
如何給接口傳遞參數值呢?
在方法的參數前面, 加上一個 @Param 註解便可。 @Param內容爲HTTP連接中參數佔位符的名稱。綁定好以後,實際這個Java接口中的參數值,會替換到@Param註解中的佔位符。
好比:因爲getById的惟一參數 userid的 @Param註解中,用到的佔位符是userid。那麼,經過調用 userAction.getById(100) ,那麼userid的值100,就會用來替換掉請求連接http://localhost:8080/user/{userid} 中佔位符userid,最終獲得的請求連接爲:http://localhost:8080/user/100。
在完成遠程API的本地代理接口的定之後,接下來的工做就是調用本地代理,這個工做也是很是的簡單。
仍是以瘋狂創客圈的實戰項目,獲取用戶信息、和用戶登陸兩個API的代理接口的調用爲例。
實戰的代碼以下:
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 瘋狂創客圈 */ //@ContextConfiguration( // locations = { "classpath:application.properties" }) //@RunWith(SpringJUnit4ClassRunner.class) //@Configuration //自動加載配置信息 //@EnableAutoConfiguration public class LoginActionTest { /* // 服務器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); } }
主要的也是最爲核心的就一步,構建一個遠程代理接口的本地實例。使用Feign.builder() 構造器模式方法,帶上一票配置方法的鏈式調用。主要的鏈式調用的配置方法介紹以下:
(1)target 配置方法
爲構造器配置本地的代理接口,和遠程的根目錄。代理接口類的每個接口方法前@RequestLine 聲明的值,最終都會加上這個根目錄。這個是最爲重要的一個配置方法。代理接口類很重要,最終Feign.builder() 構造器返回的本地代理實例類型,就這個接口。
(2)options配置方法
options方法指定鏈接超時時長及響應超時時長。
(3)retryer配置方法
retryer方法主要是指定重試策略。
(4)decoder配置方法
decoder方法指定對象解碼方式,這裏用的是基於String字符串的解碼方式。若是須要使用Jackson的解碼方式,須要在pom.xml中添加Jackson的依賴。
主要的配置方法,就介紹這些,具體使用和其餘的方法,請參見官網。
經過Feign.builder() 構造完成代理實例後,調用遠程API,就變成了調用Java函數同樣的簡單。
建議,若是是獨立調用Http服務,儘可能使用Feign。
一是簡單,
二是若是採用httpclient或其餘相對較重的框架,對初學者來講編碼量與學習曲線都會是一個挑戰。
三是,既能夠獨立使用Feign,又能夠方便後續的和Spring Could微服務框架繼承。
總之,何樂而不爲呢?
下一篇: zookeeper + netty 實現高併發IM 聊天
Java (Netty) 聊天程序【 億級流量】實戰 開源項目實戰
瘋狂創客圈 【 博客園 總入口 】