基於Thrift的java和PHP互相調用範例

首先我們看看 Thrift是什麼?

thrift是一個軟件框架,用來進行可擴展且跨語言的服務的開發。它結合了功能強大的軟件堆棧和代碼生成引擎,以構建在 C++, Java, Go,Python, PHP, Ruby, Erlang, Perl, Haskell, C#, Cocoa, JavaScript, Node.js, Smalltalk, and OCaml 這些編程語言間無縫結合的、高效的服務。

是不是感覺很酷??那我們看看怎麼玩的,網上關於 thrift 的範例不少,但是很多都千篇一律,很多都有點殘缺, 下面我們就展示一下用java來做服務端, 然後客戶端用java和php同時來寫的例子。

運行環境:

win7  x64

JDK  1.8.X

PHP 5.6

其中java部分是在在 Itellj idea裏面基於MAVEN構建的項目。

廢話不多說,上碼

1,首先在idea簡歷maven項目, pom.xml 添加如下類庫

<dependencies>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>3.8.1</version>
            <scope>test</scope>
        </dependency>

        <dependency>
            <groupId>org.apache.thrift</groupId>
            <artifactId>libthrift</artifactId>
            <version>0.9.1</version>
            <exclusions>
                <exclusion>
                    <groupId>org.slf4j</groupId>
                    <artifactId>slf4j-log4j12</artifactId>
                </exclusion>
                <exclusion>
                    <groupId>org.slf4j</groupId>
                    <artifactId>slf4j-api</artifactId>
                </exclusion>
                <exclusion>
                    <groupId>log4j</groupId>
                    <artifactId>log4j</artifactId>
                </exclusion>
            </exclusions>
        </dependency>

        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-log4j12</artifactId>
            <version>1.7.2</version>
        </dependency>
    </dependencies>

 

2, 建立 demoHello.thrift 文件內容爲

namespace java com.kedacom.demo.thriftDemo
service  HelloWorldService {
    string sayHello(1:string username)
}

 這種文件是 thrift專用的 IDL文件(Interface Description Language (IDL)), 然後再用 thrift 來生成 java的通用服務代碼,命令如下:

     thrift-0.9.3.exe -r -gen java demoHello.thrift

 thrift的WIN7可執行文件下載  http://archive.apache.org/dist/thrift/0.9.3/thrift-0.9.3.exe, 下載完設置下 系統path就可以了, 執行命令會在 同目錄下生成 gen-java 文件夾,  裏面的 com\kedacom\demo\thriftDemo 下的HelloWorldService.java 文件就是我們要用到的,這個文件是定義了我們的IDL接口引用邏輯的,是把這個RPC接口抽象出來,客戶端可以連接調用

 

3, 然後在項目的  src/main/java 目錄下建立新的package, 命名爲  com.kedacom.demo.thriftDemo,把上面的 HelloWorldService.java 拷貝到packge的目錄下面,  然後在此package新建類HelloClientDemo, HelloServerDemo, HelloWorldImpl,內容分別爲

 

HelloClientDemo

package com.kedacom.demo.thriftDemo;
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;

public class HelloClientDemo {
    public static final String SERVER_IP = "localhost";
    public static final int SERVER_PORT = 8090;
    public static final int TIMEOUT = 30000;


    public void startClient(String userName) {
        TTransport transport = null;
        try {
            transport = new TSocket(SERVER_IP, SERVER_PORT, TIMEOUT);
            // 協議要和服務端一致
            TProtocol protocol = new TBinaryProtocol(transport);
            // TProtocol protocol = new TCompactProtocol(transport);
            // TProtocol protocol = new TJSONProtocol(transport);
            HelloWorldService.Client client = new HelloWorldService.Client(protocol);
            transport.open();
            String result = client.sayHello(userName);
            System.out.println("Thrify client result =: " + result);
        } catch (TTransportException e) {
            e.printStackTrace();
        } catch (TException e) {
            e.printStackTrace();
        } finally {
            if (null != transport) {
                transport.close();
            }
        }
    }


    public static void main(String[] args) {
        HelloClientDemo client = new HelloClientDemo();
        client.startClient("Jimmy");
    }
}

 

 

 

HelloServerDemo

package com.kedacom.demo.thriftDemo;
import org.apache.thrift.TProcessor;
import org.apache.thrift.protocol.TBinaryProtocol;
import org.apache.thrift.protocol.TCompactProtocol;
import org.apache.thrift.protocol.TJSONProtocol;
import org.apache.thrift.server.TServer;
import org.apache.thrift.server.TSimpleServer;
import org.apache.thrift.transport.TServerSocket;

public class HelloServerDemo {
    public static final int SERVER_PORT = 8090;

    public void startServer() {
        try {
            System.out.println("HelloWorld TSimpleServer start ....");

            TProcessor tprocessor = new HelloWorldService.Processor<HelloWorldService.Iface>(new HelloWorldImpl());
            TServerSocket serverTransport = new TServerSocket(SERVER_PORT);
            TServer.Args tArgs = new TServer.Args(serverTransport);
            tArgs.processor(tprocessor);
            tArgs.protocolFactory(new TBinaryProtocol.Factory());
            // tArgs.protocolFactory(new TCompactProtocol.Factory());
            // tArgs.protocolFactory(new TJSONProtocol.Factory());
            TServer server = new TSimpleServer(tArgs);
            server.serve();
        } catch (Exception e) {
            System.out.println("Server start error!!!");
            e.printStackTrace();
        }
    }

    public static void main(String[] args) {
        HelloServerDemo server = new HelloServerDemo();
        server.startServer();
    }
}

 

HelloWorldImpl

package com.kedacom.demo.thriftDemo;
import org.apache.thrift.TException;
public class HelloWorldImpl implements HelloWorldService.Iface {

    public HelloWorldImpl() {
    }

    public String sayHello(String username) throws TException {
        // TODO Auto-generated method stub
        return "Hi," + username + " welcome,. this is Thrift demo!";
    }
}

 

至此我們的java版的thrift的服務端和客戶端就完成了

執行  HelloServerDemo 顯示 HelloWorld TSimpleServer start ....

執行  HelloClientDemo 顯示  Thrify client result =: Hi,Jimmy welcome,. this is Thrift demo!

 

其中核心邏輯其實是在 執行類  HelloWorldImpl 裏面, server和client的類只是按照 thrift的標準來寫好邏輯即可, 服務端和客戶端的類的標準可參考官方文檔,下面我們貼下 PHP 的客戶端實現代碼

首先我們把第二步的 文件改成

namespace php helloworld
service  HelloWorldService {
    string sayHello(1:string username)
}

執行thrift命令之後,會生成 gen-php 目錄

 

PHP客戶端代碼如下

#!/usr/bin/env php
<?php

namespace helloworld\php;

error_reporting(E_ALL);

//echo __DIR__; exit();

require_once '/opt/thrift_php/lib/Thrift/ClassLoader/ThriftClassLoader.php';

///**
use Thrift\ClassLoader\ThriftClassLoader;

//$GEN_DIR = realpath(dirname(__FILE__).'/..').'/gen-php';
$GEN_DIR = '/opt/thrift_php/mycode/gen-php';

$loader = new ThriftClassLoader();
$loader->registerNamespace('Thrift', '/opt/thrift_php/lib');  //這個是thrift源碼下載之後,這個目錄thrift-0.9.3/lib/抽離出來的
//$loader->registerNamespace('Thrift', __DIR__ . '/../../lib/php/lib');
//$loader->registerDefinition('shared', $GEN_DIR);
$loader->registerDefinition('helloworld', $GEN_DIR);
$loader->register();



use Thrift\Protocol\TBinaryProtocol;
use Thrift\Transport\TSocket;
use Thrift\Transport\THttpClient;
use Thrift\Transport\TBufferedTransport;
use Thrift\Exception\TException;
//**/


//$socket = new TSocket('localhost', 8090); 
$socket = new TSocket('192.168.17.1', 8090); 
$transport = new TBufferedTransport($socket, 1024, 1024);
$protocol = new TBinaryProtocol($transport);
$client = new \helloworld\HelloWorldServiceClient($protocol);
//print_r($client);

$transport->open();
$str = $client->sayHello("jimmyxx");
echo $str;

$transport->close();

其中 $socket = new TSocket('192.168.17.1', 8090);  這句是服務端的IP地址和運行端口, 直接在linux下 PHP 執行此文件,顯示   Hi,jimmyxx welcome,. this is Thrift demo! 成功調用了java的服務端代碼, 是不是能感覺到一點點跨編程語言的遠程RPC調用的魅力所在呢? 呵呵~~~ 範例簡單明瞭,應用到我們實際項目裏面還是要根據項目的具體情況進行一下架構設計, 比如我們就把PHP的客戶端,服務端都集成在我們的MVC框架裏面去了。

源碼地址請訪問github: https://github.com/halokid/thrift-java-php,  有用的話,記得star或者fork一下哦

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章