Java で Thrift ってみる on Windows その2

その1で環境が整ったので実際に RPC コードを作ってみる。

IDL ファイルの作成

RPC のメソッド定義にあたる IDL ファイルを作る。
お試しと言うことで単純な物を。
見ての通り String hello(String arg); 相当

Hello.thrift

service Hello
{
 string hello(1:string arg)
}

ブリッジコードの生成

thrift.exe にパスを通しておいて、以下を実行。

> thrift.exe --gen java Hello.thrift

gen-java というディレクトリができてその下に Hello.java ができていて、 これが RPC を取り扱うコードになってる。
ずらずらとコードができるけれど、ユーザがまず相手することになるのは Hello.Client, Hello.Iface, Hello.Processor の3つ。 それぞれ RPC呼び出し口、RPC受け側スタブ、RPC受け側での呼び元 という役割で、RPCした ときのメッセージの流れは次のようになってます。

Hello.Client → (Thrift) →|→ (RPC) →|→ (Thrift) → Hello.Processor → Hello.Iface
      クライアント側                                   サーバ側

お試し

お試し用一本書きコード。

import org.apache.thrift.TException;
import org.apache.thrift.protocol.TBinaryProtocol;
import org.apache.thrift.protocol.TProtocol;
import org.apache.thrift.server.TServer;
import org.apache.thrift.server.TThreadPoolServer;
import org.apache.thrift.transport.TServerSocket;
import org.apache.thrift.transport.TServerTransport;
import org.apache.thrift.transport.TSocket;
import org.apache.thrift.transport.TTransport;

public class ThriftTest {
    // RPC のハンドラ(受け側)
    // 生成された Hello.java で定義されている Hello.Iface の実装を書く
    static class HelloHandler implements Hello.Iface {
        public String hello(String arg) throws TException {
            System.out.println("called the Hello service");
            return "Hello " + arg;
        }
    }

    // main : 例外処理はサボリ
    public static void main(String[] args) {
        try {
            // 呼ばれる側=サーバ側の用意

            // RPC ハンドラ
            HelloHandler handler = new HelloHandler();
            Hello.Processor processor = new Hello.Processor(handler);
            // RPC 受付ポートの作成
            TServerTransport serverTransport = new TServerSocket(9090);
            // マルチスレッド対応サーバを使う
            final TServer server = new TThreadPoolServer(processor, serverTransport);

            // server.serve がブロックするので別スレッドで動かす
            new Thread(new Runnable() {
                public void run() {
                    System.out.println("Starting the server...");
                    server.serve();
                    System.out.println("Stopped the server...");
                }
            }).start();


            // 呼ぶ側=クライアントの用意

            // 呼び先のソケット作成
            TTransport transport = new TSocket("localhost", 9090);
            TProtocol protocol = new TBinaryProtocol(transport);

            transport.open();    // サーバに接続

            Hello.Client client = new Hello.Client(protocol);

            System.out.println("call the Hello service");
            System.out.println(client.hello("world"));       // RPCする

            transport.close();   // サーバから切断

            server.stop();    // サーバを止める
            serverTransport.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

その1で書いた 4 ファイルにクラスパスを通して実行すると次のようになる。なれば正解。

Starting the server...
call the Hello service
called the Hello service
Hello world
Stopped the server...