杰瑞科技汇

Thrift Java实例怎么写?入门示例代码?

我们将创建一个简单的用户服务,可以创建用户和根据 ID 获取用户信息。

Thrift Java实例怎么写?入门示例代码?-图1
(图片来源网络,侵删)

步骤概览

  1. 定义 Thrift 文件: 使用 .thrift 文件定义数据结构和服务的接口。
  2. 生成 Java 代码: 使用 Thrift 编译器根据 .thrift 文件生成 Java 代码。
  3. 实现服务端: 编写一个 Java 类,实现生成的 Iface 接口,并启动一个 Thrift 服务器。
  4. 编写客户端: 编写一个 Java 客户端,连接到服务器并调用服务。
  5. 运行与测试: 先启动服务端,再运行客户端进行测试。

第 1 步:定义 Thrift 文件

创建一个名为 user.thrift 的文件,这个文件将定义我们的 User 数据结构以及 UserService

user.thrift

// 指定生成的语言为 Java
namespace java com.example.thrift
// 定义一个数据结构 User
struct User {
    1: required i32 id,
    2: required string name,
    3: optional string email,
    4: optional i32 age
}
// 定义服务 UserService
service UserService {
    // 创建一个用户,返回新创建的用户信息
    User createUser(1: User user),
    // 根据 ID 获取用户
    User getUserById(1: required i32 id)
}

文件解释:

  • namespace java com.example.thrift: 指定生成的 Java 代码包名为 com.example.thrift
  • struct User: 定义一个名为 User 的结构体,类似于 Java 的类,字段前的 1:, 2: 是字段 ID,Thrift 内部使用,用于序列化。required 表示该字段是必须的,optional 表示是可选的。
  • service UserService: 定义一个名为 UserService 的服务,它包含两个方法:
    • createUser: 接收一个 User 对象,返回一个 User 对象。
    • getUserById: 接收一个 i32 类型的 id,返回一个 User 对象。

第 2 步:生成 Java 代码

你需要下载 Thrift 编译器 并配置好环境变量。

Thrift Java实例怎么写?入门示例代码?-图2
(图片来源网络,侵删)

在你的项目根目录下(user.thrift 所在目录),运行以下命令:

thrift --gen java user.thrift

执行成功后,会生成一个名为 gen-java 的目录,其结构如下:

gen-java/
└── com/
    └── example/
        └── thrift/
            ├── User.java          // 生成的 User 数据结构类
            ├── UserService.java   // 生成的服务接口
            └── UserService$Iface.java // 生成的服务实现接口(需要被实现)

这些就是 Thrift 帮我们生成的骨架代码。UserService$Iface 是我们需要在服务端实现的接口。


第 3 步:实现服务端

我们来编写服务端的代码,你需要一个 Java 项目,并将 gen-java 目录下的代码以及 Thrift 的 Java 库(libthrift-x.x.x.jar)添加到项目的 classpath 中。

Thrift Java实例怎么写?入门示例代码?-图3
(图片来源网络,侵删)

这里以 Maven 项目为例,你的 pom.xml 应该包含以下依赖:

<dependencies>
    <!-- Thrift 核心库 -->
    <dependency>
        <groupId>org.apache.thrift</groupId>
        <artifactId>libthrift</artifactId>
        <version>0.19.0</version> <!-- 请使用最新稳定版本 -->
    </dependency>
    <!-- 其他依赖,如日志 -->
    <dependency>
        <groupId>org.slf4j</groupId>
        <artifactId>slf4j-api</artifactId>
        <version>1.7.36</version>
    </dependency>
    <dependency>
        <groupId>ch.qos.logback</groupId>
        <artifactId>logback-classic</artifactId>
        <version>1.2.12</version>
    </dependency>
</dependencies>

服务端实现代码 UserServiceImpl.java

package com.example.thrift;
import org.apache.thrift.TException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.HashMap;
import java.util.Map;
/**
 * UserService 的具体实现
 */
public class UserServiceImpl implements UserService.Iface {
    private static final Logger logger = LoggerFactory.getLogger(UserServiceImpl.class);
    // 使用一个简单的 Map 来模拟数据库存储
    private final Map<Integer, User> userDatabase = new HashMap<>();
    @Override
    public User createUser(User user) throws TException {
        logger.info("Creating user: {}", user);
        // 为用户分配一个 ID (这里简单模拟,实际应用应从数据库获取)
        int newId = userDatabase.size() + 1;
        user.setId(newId);
        userDatabase.put(newId, user);
        return user;
    }
    @Override
    public User getUserById(int id) throws TException {
        logger.info("Getting user by id: {}", id);
        User user = userDatabase.get(id);
        if (user == null) {
            // 如果用户不存在,可以抛出异常或返回 null
            // 这里选择抛出异常,更符合 Thrift 的习惯
            throw new TException("User with id " + id + " not found.");
        }
        return user;
    }
}

服务器启动代码 Server.java

package com.example.thrift;
import org.apache.thrift.TProcessor;
import org.apache.thrift.protocol.TBinaryProtocol;
import org.apache.thrift.server.TServer;
import org.apache.thrift.server.TSimpleServer;
import org.apache.thrift.transport.TServerSocket;
import org.apache.thrift.transport.TTransportException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class Server {
    private static final Logger logger = LoggerFactory.getLogger(Server.class);
    private static final int PORT = 9090;
    public static void main(String[] args) {
        try {
            // 1. 创建传输层,监听指定端口
            TServerSocket serverTransport = new TServerSocket(PORT);
            // 2. 创建协议工厂,这里使用二进制协议
            TBinaryProtocol.Factory protocolFactory = new TBinaryProtocol.Factory();
            // 3. 创建处理器,将服务实现与接口绑定
            UserService.Processor<UserServiceImpl> processor = new UserService.Processor<>(new UserServiceImpl());
            // 4. 创建服务器模型,这里使用简单的单线程阻塞模型
            TServer.Args args = new TServer.Args(serverTransport)
                    .processor(processor)
                    .protocolFactory(protocolFactory);
            TServer server = new TSimpleServer(args);
            logger.info("Starting the simple server on port {}", PORT);
            // 5. 启动服务器
            server.serve();
        } catch (TTransportException e) {
            logger.error("Server failed to start", e);
        }
    }
}

第 4 步:编写客户端

客户端代码相对简单,它只需要知道服务端的地址、端口,然后调用生成的 UserService.Client 即可。

客户端代码 Client.java

package com.example.thrift;
import org.apache.thrift.TException;
import org.apache.thrift.protocol.TBinaryProtocol;
import org.apache.thrift.protocol.TProtocol;
import org.apache.thrift.transport.TSocket;
import org.apache.thrift.transport.TTransport;
import org.apache.thrift.transport.TTransportException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class Client {
    private static final Logger logger = LoggerFactory.getLogger(Client.class);
    private static final String SERVER_HOST = "localhost";
    private static final int SERVER_PORT = 9090;
    public static void main(String[] args) {
        // 1. 创建传输层,连接到服务器
        TTransport transport = new TSocket(SERVER_HOST, SERVER_PORT);
        try {
            transport.open();
            // 2. 创建协议层
            TProtocol protocol = new TBinaryProtocol(transport);
            // 3. 创建客户端
            UserService.Client client = new UserService.Client(protocol);
            // 4. 调用服务方法
            // 4.1 创建一个用户
            User newUser = new User();
            newUser.setName("Alice");
            newUser.setEmail("alice@example.com");
            newUser.setAge(30);
            User createdUser = client.createUser(newUser);
            logger.info("Created user: {}", createdUser);
            // 4.2 根据ID获取用户
            int userId = createdUser.getId();
            User fetchedUser = client.getUserById(userId);
            logger.info("Fetched user: {}", fetchedUser);
            // 5. 关闭传输层
            transport.close();
        } catch (TTransportException e) {
            logger.error("Transport error", e);
        } catch (TException e) {
            logger.error("Thrift application error", e);
        }
    }
}

第 5 步:运行与测试

  1. 启动服务端: 运行 Server.javamain 方法,你应该会在控制台看到日志:

    INFO  c.e.t.Server - Starting the simple server on port 9090
  2. 运行客户端: 在服务端运行后,运行 Client.javamain 方法,客户端的输出应该类似于:

    INFO  c.e.t.Client - Created user: User(id:1, name:Alice, email:alice@example.com, age:30)
    INFO  c.e.t.Client - Fetched user: User(id:1, name:Alice, email:alice@example.com, age:30)

    服务端的控制台也会打印出相应的日志:

    INFO  c.e.t.UserServiceImpl - Creating user: User(id:0, name:Alice, email:alice@example.com, age:30)
    INFO  c.e.t.UserServiceImpl - Getting user by id: 1

至此,一个完整的 Thrift Java 实例就完成了,这个例子涵盖了 Thrift 开发的核心流程,你可以基于此进行扩展,例如使用更高效的 TThreadPoolServerTNonblockingServer,以及更复杂的数据类型和业务逻辑。

分享:
扫描分享到社交APP
上一篇
下一篇