Getting Started with Apache Thrift
Overview
This article explains how to write Thrift services and clients in several modes, including blocking, non-blocking, and asynchronous execution. The examples use Apache Thrift and Java.
Prerequisites
Apache Thrift must be installed first. For installation instructions, see the Apache Thrift overview.
Developing with Apache Thrift
Defining a Service with a Thrift Script
After installation, create a Thrift IDL file. A single IDL file can generate code for multiple languages.
namespace java com.devkuma.thrift.tutorial
typedef i64 long
typedef i32 int
service ArithmeticService {
long add(1:int num1, 2:int num2),
long multiply(1:int num1, 2:int num2),
}
The namespace becomes the Java package structure, such as com.devkuma.thrift.tutorial. Thrift supports 32-bit and 64-bit integer types, and typedef can be used to rename them. A service can be considered similar to a class that exposes methods for server-to-server or server-to-client communication.
Generate Java code with the Thrift compiler.
thrift --gen <language> <Thrift filename>
% thrift -r --gen java arithmetic.thrift
If the command succeeds, ArithmeticService.java is generated under gen-java/com/devkuma/thrift/tutorial/.
Creating a Java Project
Create a Java project with Gradle and add the libraries needed for Thrift communication, such as TSocket and TTransport.
dependencies {
implementation 'org.apache.thrift:libthrift:0.18.1'
implementation 'javax.annotation:javax.annotation-api:1.3.2'
implementation 'ch.qos.logback:logback-classic:1.4.7'
implementation 'org.slf4j:slf4j-api:2.0.7'
}
Implementing the Service
Implement the generated skeleton interface, ArithmeticService.Iface.
public class ArithmeticServiceImpl implements ArithmeticService.Iface {
public long add(int num1, int num2) throws TException {
return num1 + num2;
}
public long multiply(int num1, int num2) throws TException {
return num1 * num2;
}
}
Blocking Mode
In blocking mode, the server thread waits while I/O is being processed. The example uses TThreadPoolServer to process incoming requests with a thread pool.
TServerSocket serverTransport = new TServerSocket(7911);
ArithmeticService.Processor processor =
new ArithmeticService.Processor(new ArithmeticServiceImpl());
TServer server = new TThreadPoolServer(
new TThreadPoolServer.Args(serverTransport).processor(processor));
server.serve();
The client opens a socket, creates a protocol, and calls methods through ArithmeticService.Client.
TTransport transport = new TSocket("localhost", 7911);
TProtocol protocol = new TBinaryProtocol(transport);
ArithmeticService.Client client = new ArithmeticService.Client(protocol);
transport.open();
long addResult = client.add(100, 200);
long multiplyResult = client.multiply(20, 40);
When the server and client are run, the result should be similar to:
Add result: 300
Multiply result: 800
TBinaryProtocol encodes data exchanged between the server and client. Other available protocols include TCompactProtocol, TDebugProtocol, TDenseProtocol, and TJSONProtocol.
Non-blocking Mode
A non-blocking server uses TNonblockingServerSocket and TNonblockingServer. It can receive other requests while an earlier request is being handled.
TNonblockingServerTransport serverTransport =
new TNonblockingServerSocket(7911);
ArithmeticService.Processor processor =
new ArithmeticService.Processor(new ArithmeticServiceImpl());
TServer server = new TNonblockingServer(
new TNonblockingServer.Args(serverTransport).processor(processor));
server.serve();
The client uses TFramedTransport wrapping a normal TSocket. A non-blocking server requires clients to use framed transport so the transmitted data can be structured correctly.
TTransport transport = new TFramedTransport(new TSocket("localhost", 7911));
TProtocol protocol = new TBinaryProtocol(transport);
ArithmeticService.Client client = new ArithmeticService.Client(protocol);
Running the non-blocking server and client produces the same arithmetic results as the blocking example.
Asynchronous Mode
In asynchronous mode, the client registers callbacks that are invoked when requests complete. The asynchronous client cannot communicate correctly with the blocking server. Use TNonblockingSocket and the generated ArithmeticService.AsyncClient.
ArithmeticService.AsyncClient client =
new ArithmeticService.AsyncClient(
new TBinaryProtocol.Factory(),
new TAsyncClientManager(),
new TNonblockingSocket("localhost", 7911));
client.add(200, 400, new AddMethodCallback());
Each concurrent asynchronous operation needs its own client instance. If the same client tries to execute another method while a request is still running, Thrift raises an IllegalStateException.