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.qiyuesuo.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复制代码
相关文章
相关标签/搜索