安装Thrift
略。
定义IDL文件
DemoService.thrift
namespace php Woojean.Rpc.Demo // PHP项目的命名空间
namespace java com.woojean.rpc.demo // Java项目的命名空间
// 异常定义
exception RequestException {
}
// 参数定义
struct Param
{
1:required string s1,
2:required string s2,
}
// 服务定义
service DemoService
{
// 定义一个连接字符串的方法,用一个指定的分隔符连接Param的所有属性,并返回一个完整的字符串
string joinString(1:required Param p, 2:required string sep)
throws (1:RequestException e);
}
生成文件
生成PHP文件
thrift -gen php:server DemoService.thrift
将会生成以下文件:
gen-php/Woojean/Rpc/Demo/DemoService.php // 存放Rpc接口约定interface DemoServiceIf,以及PHP版的服务端处理程序、客户端class DemoServiceProcessor、class DemoServiceClient
gen-php/Woojean/Rpc/Demo/Types.php // 存放自定的类型,本例是class RequestException和class Param
生成Java文件
thrift --gen java DemoService.thrift
将会生成以下文件:
gen-java/com/woojean/rpc/demo/DemoService.java
gen-java/com/woojean/rpc/demo/Param.java
gen-java/com/woojean/rpc/demo/RequestException.java
编写Java服务端项目
服务端项目文件结构
服务端用maven构建,项目结构如下:
Service/
lib/
... // thrift、log4j等jar包
src/
/main
/java
/com
/woojean
/rpc
/demo
DemoService.java
Param.java
RequestException.java
RpcHandler.java // 定义实际被调用的方法
RpcServer.java // 实现了一个简单的Server
/resources
/META-INF
MANIFEST.MF // 打包后使用的MANIFEST信息
/target
pom.xml
pom.xml
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
4.0.0
com.woojean.rpc
demo
jar
1.0
aid
http://maven.apache.org
org.apache.maven.plugins
maven-jar-plugin
src/main/resources/META-INF/MANIFEST.MF
true
junit
junit
3.8.1
test
org.apache.thrift
libthrift
0.10.0
org.slf4j
slf4j-log4j12
1.7.5
MANIFEST.MF
Manifest-Version: 1.0
Created-By: 1.8.0_121 (Oracle Corporation)
Main-Class: com.woojean.rpc.demo.RpcServer
Class-Path: lib/libthrift-0.10.0.jar lib/log4j-1.2.14.jar lib/slf4j-api-1.5.11.jar lib/slf4j-log4j12-1.5.11.jar
RpcHandler.java
package com.woojean.rpc.demo;
import org.apache.thrift.TException;
public class RpcHandler implements DemoService.Iface{
@Override
public String joinString(Param p,String sep) throws TException {
return p.getS1() + sep + p.getS2();
}
}
RpcServer.java
package com.woojean.rpc.demo;
import org.apache.thrift.TMultiplexedProcessor;
import org.apache.thrift.server.TThreadPoolServer;
import org.apache.thrift.transport.*;
import org.apache.thrift.server.TServer;
public class RpcServer {
private void start() {
try {
TServerSocket serverTransport = new TServerSocket(9524);
DemoService.Processor demoProcessor = new DemoService.Processor(new RpcHandler());
TMultiplexedProcessor processor = new TMultiplexedProcessor();
processor.registerProcessor("DemoService", demoProcessor);
TServer server = new TThreadPoolServer(new TThreadPoolServer.Args(
serverTransport).processor(processor));
System.out.println("Starting server on port 9524 ...");
server.serve();
} catch (TTransportException e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
}
}
public static void main(String args[]) {
RpcServer srv = new RpcServer();
srv.start();
}
}
编写PHP客户端项目
客户端项目文件结构
Client/
/Library
/Thrift // Thrift的PHP版库
...
/Woojean
/Rpc
/Demo
DemoSevice.php
Types.php
DemoClient.php // 实际的客户端代码
DemoClient.php
define('DIR_BACKEND', dirname(__DIR__) . '/Client');
var_dump(DIR_BACKEND);
// 用于自动寻找并加载Thrift库中的类
spl_autoload_register(function ($clientClass) {
try {
$class = str_replace('\\', '/', $clientClass);
$filePath = DIR_BACKEND.'/Library/' . $class . '.php';
require_once $filePath;
} catch (\Exception $e) {
echo $e->getMessage();
var_dump($clientClass);
}
});
// 引用Thrift生成的文件
require_once DIR_BACKEND .'/Woojean/Rpc/Demo/DemoService.php';
require_once DIR_BACKEND .'/Woojean/Rpc/Demo/Types.php';
// Demo
use \Thrift\Transport\TSocket;
use \Thrift\Transport\TBufferedTransport;
use \Thrift\Protocol\TBinaryProtocol;
use \Thrift\Protocol\TMultiplexedProtocol;
use \Thrift\Exception\TException;
use \Woojean\Rpc\Demo\DemoServiceClient;
use \Woojean\Rpc\Demo\Param;
use \Woojean\Rpc\Demo\RequestException;
try {
// 注意端口号与服务端一致
$socket = new TSocket('0.0.0.0', '9524', TRUE);
// 注意传输协议与服务端一致
$transport = new TBufferedTransport($socket, 1024, 1024);
$protocol = new TBinaryProtocol($transport);
$protocol = new TMultiplexedProtocol($protocol, "DemoService"); // 注意服务名与服务端注册的一致
// 构造参数
$params = new \Woojean\Rpc\Demo\Param();
$params->s1 = 'Hello';
$params->s2 = 'World!';
$sep = '+';
// 构造客户端
$client = new DemoServiceClient($protocol);
$transport->open();
// 调用Rpc方法
$ret = $client->joinString($params, $sep);
// 打印调用结果
var_dump($ret); // Hello+World!
$transport->close();
} catch (RequestException $ex) {
print 'RequestException: ' . $ex->getMessage() . "\n";
}
运行
启动服务端
cd Service/target/
java -jar demo-1.0.jar
运行客户端
输出:
Hello+World!
Thrift生成文件简析
根据本例生成的文件,简单解析Thrift生成的文件及其作用。
PHP
PHP共生成2个文件:DemoService.php和Types.php,路径与在IDL中定义的命名空间一致(Woojean\Rpc\Demo)。其中DemoService.php的命名是由于在IDL文件中定义了:
// 服务定义
service DemoService
{
// ...
而Types.php的命名是统一的,用于存放在IDL文件中自定义的各种类型。
Types.php的内容
class RequestException extends TException
class Param // 含s1和s2两个属性
Types.php中定义的每个类都实现了以下方法:getName()、read($input)、write($output)。
DemoService.php的内容
interface DemoServiceIf // 定义了方法joinString(\Woojean\Rpc\Demo\Param $p, $sep)
class DemoServiceClient implements \Woojean\Rpc\Demo\DemoServiceIf
class DemoService_joinString_args // Rpc方法joinString的参数(面向传输的封装:参数也需要传输)
class DemoService_joinString_result // Rpc方法joinString的返回值(面向传输的封装:返回值也需要传输)
class DemoServiceProcessor // PHP版的服务端处理类
Java
Java共生成3个文件:
DemoService.java
Param.java
RequestException.java
因为Java中公共类必须与文件同名,所以每个自定义类型都单独是一个文件。
详略。