Apache Thrift入门简单实战(Java)

来源:互联网 发布:aria2 mac 编辑:程序博客网 时间:2024/05/29 18:53

Thrift是Apache旗下开源项目,官网地址:thrift.apache.org,本篇的开发语言使用Java。

1.Thrift协议:Thrift支持的协议包含二进制(TBinary,TBinarySortableProtocol),JSON(TJSONProtocol,TSimpleJsonProyocol),compact协议(TCompactProtocol)等等,默认是使用的二进制协议,而二进制协议正好解决了大数据量情况下的传输问题。

2.跨语言:支持 C++, Java, Python, PHP, Ruby, Erlang, Perl, Haskell, C#, Cocoa, JavaScript, Node.js, Smalltalk, OCaml and Delphi 语言之间的消息传输,达到无缝对接,高效快速的目的。

3.Mac下安装Thrift,使用HomeBrew进行安装:brew install thrift,等待运行完成,输入thrift -version显示thrift的版本号说明安装成功。(如果没有安装HomeBrew的可以查看https://brew.sh/index_zh-cn.html安装方法)开始Thrift实战:创建thrift文件,命名为person.thrift,添加struct和service,struct相当于c语言里面的结构体,学过c的都会感觉很熟悉,service代表接口,客户端和服务端通信的接口。

namespace java com.thrift   // namespace相当于java中的packagestruct User { // 结构实体1: i32 id;2: string name;3: i32 age;4: string phone;5: string address;}service QueryService { // 接口User queryUser(1:i32 id);User addUser(1:User uer);list<User> getAll();void remove(1:i32 id);}
Thrift数据类型:
··bool:布尔值 (true or false), 1个字节··byte:有符号字节··i16:16位有符号整型··i32:32位有符号整型··i64:64位有符号整型··double:64位浮点型··string:未知编码或者二进制的字符串使用Thrift生成客户端和服务端代码,格式:
thrift --gen java person.thrift
会在person.thrift同文件夹下生成一个名为gen-java的文件夹,里面的内容即为生成的java代码,添加了namespace后会有相应的文件夹,java代码中有package信息。比如namespace java com.test,生成的两个java类中会是package com.test,生成的文件目录如下:
com  +-test     +-User.java     +-QueryService.java
将生成的java文件copy到maven项目中,注意对应的包名要相同。在eclipse下新建maven工程。导入thrift依赖包,目前最新的版本是0.10.0
<dependency>  <groupId>org.apache.thrift</groupId>  <artifactId>libthrift</artifactId>  <version>0.10.0</version></dependency>

Thrift生成了接口,接下来是编写接口的实现类。新建java类:QueryServiceImpl 实现QueryService.Iface接口。然后重写queryPerson()和queryPhone()方法。

package com.thrift.server;import java.util.List;import org.apache.thrift.TException;public class QueryServiceImp implements QueryService.Iface {        @Override    public User queryUser(int id) throws TException {        String query = "select * from user u where u.id = " + id + "";        User user = JdbcConnector.executeAll(query).get(0);        return user;    }    @Override    public User addUser(User uer) throws TException {        StringBuilder save = new StringBuilder("insert into user(id, name, address, age, phone) values (");        save.append(uer.getId()).append(",'").append(uer.getName()).append("','")        .append(uer.getAddress()).append(",").append(uer.getAge()).append(",'")        .append(uer.getPhone()).append(")");                return JdbcConnector.execute(save.toString());    }    @Override    public List<User> getAll() throws TException {        String all = "select * from user";        return JdbcConnector.executeAll(all);    }    @Override    public void remove(int id) throws TException {        JdbcConnector.remove("");    }}
JdbcConnector类:用于Jdbc连接,这里使用mysql数据库。
package com.thrift.server;import java.sql.Connection;import java.sql.DriverManager;import java.sql.ResultSet;import java.sql.SQLException;import java.sql.Statement;import java.util.ArrayList;import java.util.List;public class JdbcConnector {        public static final String DB_DRIVER = "com.mysql.jdbc.Driver";      public static final String DB_URL = "jdbc:mysql://localhost:3306/thrift?"            + "characterEncoding=utf-8&useSSL=false";      public static final String DB_USER = "root";      public static final String DB_PASSWORD = "root";          public static List<User> executeAll(String query) {        Statement statement = getStatement();        try {            ResultSet resultSet = statement.executeQuery(query);            List<User> users = new ArrayList<>();            while(resultSet.next()) {                User user = new User();                user.setId(resultSet.getInt(1));                user.setAddress(resultSet.getString(3));                user.setAge(resultSet.getInt(4));                user.setName(resultSet.getString(5));                user.setPhone(resultSet.getString(6));                users.add(user);            }            return users;        } catch (SQLException e) {            e.printStackTrace();        }        return null;    }        public static boolean remove(String query) {        Statement statement = getStatement();        try {            return statement.execute(query);        } catch (SQLException e) {            e.printStackTrace();        }        return false;    }        private static Statement getStatement() {        Connection conn = null;        try {            Class.forName(DB_DRIVER);            conn = DriverManager.getConnection(DB_URL,DB_USER,DB_PASSWORD);            return conn.createStatement();        } catch (Exception e) {            e.printStackTrace();        }        return null;    }}
编写服务端监听和处理代码,用于监听客户端的请求。
package com.thrift.server;import org.apache.thrift.TProcessorFactory;import org.apache.thrift.protocol.TBinaryProtocol;import org.apache.thrift.server.TNonblockingServer;import org.apache.thrift.server.TServer;import org.apache.thrift.transport.TFramedTransport;import org.apache.thrift.transport.TNonblockingServerSocket;import org.apache.thrift.transport.TTransportException;public class ThriftServer {    private final static int DEFAULT_PORT = 60587; // 端口    private static TServer server = null;    @SuppressWarnings({ "rawtypes", "unchecked" })    public static void main(String[] args) {        try {            TServerSocket socket = new TServerSocket(DEFAULT_PORT);            AbstractServerArgs args = new TServer.Args(socket);            args.processorFactory(new TProcessorFactory(processor));            args.protocolFactory(new TBinaryProtocol.Factory());            args.transportFactory(new TFramedTransport.Factory());                        server = new TSimpleServer(args);            server.serve();            } catch (TTransportException e) {                e.printStackTrace();            }    }}
运行main()方法,执行监听。接下来是编写客户端测试的代码,新建Client类
package com.client;import org.apache.thrift.protocol.TBinaryProtocol;import org.apache.thrift.protocol.TProtocol;import org.apache.thrift.transport.TFramedTransport;import org.apache.thrift.transport.TSocket;import org.apache.thrift.transport.TTransport;public class Client {    public static void main(String[] args) {        // 封装了I/O层的通用传输实现        TTransport tTransport = getTTransport();        try {            // thrift的二进制协议实现(可以设置严格读和严格写)            TProtocol protocol = new TBinaryProtocol(tTransport, true, true);                        // Client继承自TServiceClient,用于与TService实现通信协议和传输。            QueryService.Client client = new QueryService.Client(protocol);            Person person = client.queryPerson("aaa",23);            System.out.println("当前Person ID:" + person.id);            System.out.println("当前Person年龄:" + person.age);            System.out.println("当前Person名字:" + person.name);            System.out.println("当前Person电话:" + person.phone);        } catch (Exception e) {            e.printStackTrace();        } finally {            tTransport.close();        }    }    private static TTransport getTTransport() {        try {            TTransport tTransport = new TFramedTransport(new TSocket("localhost", 60587, 5000));            if (!tTransport.isOpen()) {                tTransport.open();            }            return tTransport;        } catch (Exception e) {            e.printStackTrace();        }        return null;    }}
这里注意,如果客户端和服务端写在不同的工程里面,那么Thrift生成的两个类需要在客户端和服务端都存在。运行客户端程序,即可看到结果,可以往mysql数据库的user表中添加一点数据,再执行查询。