Skip to content
 

Apache ThriftのクライアントサイドをJavaで動かす

前回前々回の記事で、Apache ThriftでRPCを定義し、コードを生成してサーバを立てるところまで行きました。

今回はクライアントサイドです。こちらもJavaで動かしてみたいと思います。

ThriftでJavaのコードを生成するところは、前回でも前々回でも解説したので、今回は省略します。

# thrift --gen java TinyCalc.thrift

ってやって、TinyCalc.javaが生成できているつもりで読んでください。

Eclipseのプロジェクトを作る

今回もEclipseのプロジェクトとして作ります。通常のJavaアプリケーションプロジェクトを作ってください。プロジェクト名はthrift-test-clientとしました。

毎度ですが僕はMavenを使っているので、以下のpom.xmlを用意しました。

pom.xml

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
 <modelVersion>4.0.0</modelVersion>

 <groupId>jp.ohnaka.thrift</groupId>
 <version>1.0.0-SNAPSHOT</version>
 <artifactId>thrift-test-client</artifactId>
 <name>Apache Thrift test Server</name>

 <dependencies>
  <dependency>
   <groupId>org.apache.thrift</groupId>
   <artifactId>libthrift</artifactId>
   <version>0.6.1</version>
  </dependency>

  <!-- Logging -->
  <dependency>
   <groupId>org.slf4j</groupId>
   <artifactId>slf4j-api</artifactId>
   <version>1.6.1</version>
  </dependency>
  <dependency>
   <groupId>ch.qos.logback</groupId>
   <artifactId>logback-core</artifactId>
   <version>0.9.16</version>
  </dependency>
  <dependency>
   <groupId>ch.qos.logback</groupId>
   <artifactId>logback-classic</artifactId>
   <version>0.9.16</version>
  </dependency>

  <!-- Testing -->
  <dependency>
   <groupId>junit</groupId>
   <artifactId>junit</artifactId>
   <version>4.8.1</version>
   <scope>test</scope>
  </dependency>
 </dependencies>

 <build>
  <plugins>
     <plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-compiler-plugin</artifactId>
    <version>2.1</version>
    <configuration>
     <encoding>UTF-8</encoding>
     <source>1.6</source>
     <target>1.6</target>
    </configuration>
   </plugin>
  </plugins>
 </build>
</project>

Thrift本体のjarと、slf4jのライブラリなどを足しています。依存ライブラリとして httpclientなども入ります。最終的にMavenが解決したライブラリは以下のようになりました。

プロジェクトが生成できたら、Thriftが生成した TinyCalc.javaをソースフォルダにコピーしてください。

クライアントサイドからサービスを呼び出す

それでは早速、クライアントからサーバサイドのサービスを呼び出すコードを書いてみます。

Client.java

import org.apache.thrift.TException;
import org.apache.thrift.protocol.TBinaryProtocol;
import org.apache.thrift.protocol.TProtocol;
import org.apache.thrift.transport.THttpClient;

public class Client {

    public static void main(String[] args) throws Exception {
        // 接続先のURLを指定
        THttpClient httpClient = new THttpClient("http://localhost:8080/thrift-test-server/calc");
        // バイナリプロトコルを使用(サーバ側と合わせる)
        TProtocol protocol = new TBinaryProtocol(httpClient);
        // クライアントスタブを作成
        TinyCalc.Client client = new TinyCalc.Client(protocol);

        try {
            httpClient.open();

            // サーバ側のsumメソッドを呼び出す
            double sum = client.sum(1.0, 2.2);
            System.out.println("1.0 + 2.2 =" + sum);
            // サーバ側のsubtractメソッドを呼び出す
            double sub = client.subtract(5.3, 3.4);
            System.out.println("5.3 - 3.4 =" + sub);
            httpClient.close();

        } catch (TException e) {
            e.printStackTrace();
        }
    }

}

まずトランスポート層として、THttpClientを作ります。その際、接続先URLとして、サーバサイドで作成したサーブレットのURLを指定する必要があります。今回は http://localhost:8080/thrift-test-server/calc となります。

次に、THttpClientのオブジェクトをプロトコルハンドラに渡します。今回はサーバサイドをTBinaryProtocolにしたので、クライアント側もTBinaryProtocolを使って作成しています。

最後にThriftが生成した TinyCalc.Clientをnewします。

生成されたTinyCalc.ClientオブジェクトはTinyCalc.Ifaceを実装したクラスなので、サーバサイドで定義したTinyCalcHandlerと同じ sum()メソッドと subtract()メソッドを持っています。もうお分かりだと思いますが、クライアント側のsum()メソッドを呼び出すと、サーバ側のsum()メソッドが呼び出されるわけです。

なお、実際に呼び出す為には、THttpClientのopen()メソッドを呼んでおき、必要がなくなったらclose()する必要があります。

実行結果

Eclipseの実行メニューから Clinet.javaをJavaアプリケーションとして起動してください。

コンソールに足し算と引き算の結果が表示されました!

めでたしめでたし。

感想

動かしてみた感想ですが、導入にビルドが必要だったり、ちょっと敷居が高いかなという印象はあります。しかし、今後、さまざまな有名サービスが、「うちのAPIはこれです」といって Thriftの定義ファイルを公開するのがトレンドになるかもしれません。

もしそういう時代になったら、「エンジニアが手元に Thriftをインストールしておくのは常識」と言われるようになるかもしれませんね。

僕は今までRPCを作る時は、XML-RPCを使う事が多かったです。XML-RPCもプラットフォーム非依存なRPCなのですが、実際にはXML−RPCの拡張モードを使わないと、オブジェクトや例外の伝送ができません。僕はクライアントもサーバもJavaだったということもあって、 拡張モードを使ってしまっていたのですが、これだと他の言語から呼び出すのは難しくなります。

Thriftではプリミティブ型だけでなく、構造体も定義できるようなので、互換性を失わずにXML-RPCの拡張モードのような事ができます。また、コード生成のサポートがあるので、構造体に対応した値クラスの定義などを言語ごとにいちいち作る必要もありません。

次回はこの構造体のあたりや例外の扱いを試してみたいと思います。

コメントをどうぞ