1. 程式人生 > >Feign - HTTP介面呼叫- 單獨使用 - 實戰

Feign - HTTP介面呼叫- 單獨使用 - 實戰

目錄

瘋狂創客圈 Java 分散式聊天室【 億級流量】實戰系列之 -26【 部落格園 總入口


寫在前面

​ 大家好,我是作者尼恩。目前和幾個小夥伴一起,組織了一個高併發的實戰社群【瘋狂創客圈】。正在開始高併發、億級流程的 IM 聊天程式 學習和實戰

​ 在瘋狂創客圈的 億級流程的 IM 聊天程式 學習專案中,短連線Web伺服器和長連線IM伺服器之間,是相互配合的。在分散式叢集的環境下,使用者首先通過短連線登入Web伺服器。Web伺服器在完成使用者的賬號/密碼驗證,返回uid和token時,還需要通過一定策略,獲取目標IM伺服器的IP地址和埠號列表,返回給客戶端。客戶端開始連線IM伺服器,連線成功後,傳送鑑權請求,鑑權成功則授權的長連線正式建立。

​ 短連線的呼叫,使用Feign 技術。下面是詳解。

​ 看完之後,Feign 獨立使用,完全可以替換掉目前的Http 客戶端呼叫方法。

​ 1.1. Feign短連線Restful呼叫

一般來說,短連線的服務介面,都是基於應用層Http協議的Http api 或者RESTful api實現,通過JSON文字格式返回資料。如何在Java服務端呼叫其他節點的Http api 或者RESTful api呢?

至少有以下幾種方式:

(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了。

1.1.1. 短連線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技術來實現。

1.1.2. 申明遠端介面的本地代理

如何通過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。

1.1.3. 遠端API的本地呼叫

在完成遠端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 聊天


瘋狂創客圈 億級流量 高併發IM 學習實戰

  • Java (Netty) 聊天程式【 億級流量】實戰 開源專案實戰

  • Netty 原始碼、原理、JAVA NIO 原理
  • Java 面試題 一網打盡
  • 瘋狂創客圈 【 部落格園 總入口 】