Thrift IDL使用方式

I.背景

衆所周知,Thrift是一個RPC的框架,其可用於不一樣語言之間的服務相互調用。好比最近接觸到的一個運用環境:
*前端使用Node.Js重構了部分咱們的老舊代碼(先後端未分離的SpringBoot項目),咱們後端使用zookeeper+Thrift爲新的Node.Js前端項目提供基本的DAO層服務支持*
因此基於這個項目,我大概瞭解了一下Thrift,該文章則均以Java爲基礎語言。前端


II.如何入門

由於後端已經有一套服務註冊和暴露機制,因此服務已是RPC的形式,因此咱們僅須要使用Thrift IDL來重寫一遍咱們須要暴露的方法便可,Thrift IDL有兩個比較好的參考選擇:java

  • Thrift 類型說明能夠參考官方文檔: Thrift Type,簡單來講,thrift基本支持全部的Java基本類型以及引用類型:bool(boolean)、byte(byte)、i16(short)、i32(int)、i64(long)、double(double)、string(String)、binary(byte[])以及一些經常使用容器和自建類型(Struct);
  • Thrift IDL的書寫規範則能夠參考Thrift: The Missing Guide,這個文檔相較於官方文檔有更多的例子能夠參考。

III.TIPS

  • 不少參考和學習文檔,都將servicesstruct放在一個.thrift文件中,這種方式將service和其所需的struct綁定在一塊兒,會致使個別struct重複出如今多個.thrift文件中,致使大量的代碼重複。因此,應該與Java的編碼風格保持一致,採用POJO類(struct)+接口(services)的方案,利用include關鍵字,將struct引進services中使用
  • Thrift支持基本全部的Java基本類型,可是注意是基本類型,相似於Java中的Integer、Boolean、Long、Double等基本類型包裝類是不支持的,或許你可使用struct實現一個相似的包裝類結構進行數據承載。
  • Thrift支持enum枚舉類型,可是若是沒有description的枚舉類型也能夠直接使用string來承接。
  • Thrift是經過序列化和反序列化來獲取對應struct結構體的數據的,因此struct中的數據順序必定要和java文件中的一致,不然可能會出現數據對應關係錯亂或者數據丟失。
  • 在編寫struct體時,要注意java對象父級,若是父級中含有變量,不要忘記其變量的書寫,且順序必定在前面。
  • 如非必要,java對象中的常量能夠不出如今thrift idlstruct結構體中。
  • 時間Date咱們固定使用timestamp時間戳的形式傳遞,即long型。

IV. 例子

咱們如今有一個Account對象,須要將其變爲thrift文件,Account的結構以下:node

public class Account extends BaseEntity implements SecurityUser{

        private static final long serialVersionUID = 1L;
        public static final String PASSWORD_TIME = "passwordTime";
    
        private String password;                            // 密碼
        private Date createTime;                            // 建立時間
        private Date lastLoginTime;                         // 最後登陸時間
        private int loginCount = 0;                         // 登陸次數
        private boolean enabled = true;
        private Date passwordTime;                          //密碼修改時間
        private boolean freeze;                             //帳戶是否被凍結
    
        //該帳戶的綁定信息,非持久化字段
        @Transient
        private Set<Binding> bindings = new HashSet();
    
        @Transient
        private String name;//保存登陸時用的用戶名,非持久化字段

        //省略getter和setter
  }

根據上述結構咱們能夠書寫以下的Account.thrift:apache

/**
  * 帳戶信息
  */
struct Account{
    1: string password,    //密碼
    2: i64 createTime,     //建立時間
    3: i64 lastLoginTime,  //最後登陸時間
    4: i32 loginCount,     //登錄次數
    5: bool enabled=true,
    6: i64 passwordTime,   //密碼修改時間
    7: bool freeze,        //帳戶是否被凍結
}

可是通過測試前端調用接口獲取到的Account信息,要麼數據錯位,要麼數據丟失,問題出在哪裏呢?這時,咱們發現Account對象繼承了BaseEntity,實現了SecurityUser,咱們去查看一下繼承的BaseEntity對象:後端

public abstract class BaseEntity extends IdEntity implements Cacheable, TypeAliases{
    
    private static final long serialVersionUID = 1L;
    
    private static final String CACHE_NAMESPACE = "entity" ;

    public BaseEntity() {
        super();
    }

    public BaseEntity(Long id) {
        super(id);
    }
    
    //省略下方代碼
}

咱們發現其中並無很是量變量,可是BaseEntity又繼承了IdEntity,因此咱們得再去看一看IdEntity:框架

public abstract class IdEntity implements Serializable{

    private static final long serialVersionUID = -1L;

    /**
     * Hibernate JPA環境中使用@GenericGenerator註解生成主鍵
     */
    @Id
    @GeneratedValue(generator = "longIdGenerator")
    @GenericGenerator(name = "longIdGenerator", strategy = "net.rekent.framework.id.LongIdGenerator")
    protected Long id;
    
    public IdEntity() {
        super();
    }
    
    public IdEntity(Long id) {
        super();
        this.id = id;
    }

    //省略getter和setter
}

這時咱們發現IdEntity中含有一個Id的變量,因此咱們須要重構一下剛剛書寫的Account.thriftide

/**
  * 帳戶信息
  */
struct Account{
    1: i64 id,          //帳戶Id
    2: string password,  //密碼
    3: i64 createTime,  //建立時間
    4: i64 lastLoginTime, //最後登陸時間
    5: i32 loginCount, //登錄次數
    6: bool enabled,
    7: i64 passwordTime,  //密碼修改時間
    8: bool freeze, //帳戶是否被凍結
}

書寫完Account.thrift後,咱們須要寫其相應的接口即service,查看Interface AccountService:學習

public interface AccountService {
    
    /**
     * 建立帳戶
     * @param account
     * @return 返回建立後的Account對象
     */
    Account create(Account account);
    
    /**
     * 更新帳戶信息
     * @param account
     * @return
     */
    boolean update(Account account);
    
    /**
     * 修改開放平臺密碼  傳入的 密碼是未加密的
     * @param username
     * @param newPassword
     * @return
     */
    boolean updatePasswd(String username, String newPassword);
    
    /**
     * 重置密碼
     * @param username 用戶名
     * @param newPassword 新密碼
     */
    void resetPasswd(String username, String newPassword);

    /**
     * 驗證用戶名和密碼是否匹配
     * @param username
    * @param password
     */
    boolean matches(String username,String password);
}

有不少方法,可是若是前端只須要用到校驗用戶名和密碼的方法,那麼我就只須要暴露建立帳戶的方法,即:測試

include "Account.thrift"

service AccountService{
    /*
     * 校驗用戶名和密碼
     */
    bool matches(1: string username,2: string password),
}

這樣咱們就完成了一個關於用戶名和密碼的校驗方法的thrift idl文檔的書寫,前端須要執行thrift的一條語句對文件進行編譯,以node.js爲例(具體可參考:Apache Thrift Tutorialui

thrift --gen <language> <Thrift filename>

thrift -r --gen js:node Account.thrift
thrift -r --gen js:node AccountService.thrift
相關文章
相關標籤/搜索