本文介绍下ubuntu下,基于C++从源码构建thrift,并编写典型的服务器和客户端。并基于thrift的IDL构建java库,作为客户端调用对应的服务。
系统环境
$ lsb_release -a
No LSB modules are available.
Distributor ID: Ubuntu
Description: Ubuntu 24.04.3 LTS
Release: 24.04
Codename: noble
安装Thrift支持C++与Java
基于参考资料,了解Thrift C++与Java模块对组件的依赖。这里特别注意,使用的gradle与java版本之间也有依赖关系。
# thrift依赖automake来构建
sudo apt-get update
sudo apt-get install libtool libtool-bin
sudo apt-get install automake bison flex g++ \
git libboost-all-dev libevent-dev \
libssl-dev libtool make pkg-config
# C
sudo apt install libglib2.0-dev
# Java * kotlin
# Gradle 8.14.3 可通过下载后手工安装
sudo apt install -y openjdk-11-jdk
# 下载稳定版本的源码包
wget http://archive.apache.org/dist/thrift/0.22.0/thrift-0.22.0.tar.gz
tar zxvf thrift-0.22.0.tar.gz
cd thrift-0.22.0
# 构建并安装,中间可能有错误,针对性修改
./bootstrap.sh
./configure --prefix=/home/gaoyong/soft/thrift/ --with-ruby=no --with-go=no --with-perl=no --with-php=no --with-csharp=no \
--with-erlang=no --with-lua=no --with-nodejs=no --without-python
make CPPFLAGS=-DFORCE_BOOST_SMART_PTR -j 4 -s
make install本文支持了四个语言,可在执行configure之后看到
C (glib):
Using glib version ........ : 2.80.0
C++ Library:
C++ compiler .............. : g++ -std=c++11
Build TZlibTransport ...... : yes
Build TNonblockingServer .. : yes
Build TQTcpServer (Qt5) ... : no
C++ compiler version ...... : g++ (Ubuntu 13.3.0-6ubuntu2~24.04) 13.3.0
Java Library:
Using gradle .............. : /home/gaoyong/.gradle/wrapper/dists/gradle-8.14.3-bin/cv11ve7ro1n3o1j4so8xd9n66/gradle-8.14.3/bin/gradle
Using java ................ : java
Using javac ............... : javac
Using Gradle version ...... : Gradle 8.14.3
Using java version ........ : openjdk version "11.0.28" 2025-07-15
Kotlin (Test Only) Library:
Using gradle .............. : /home/gaoyong/.gradle/wrapper/dists/gradle-8.14.3-bin/cv11ve7ro1n3o1j4so8xd9n66/gradle-8.14.3/bin/gradle
Using java ................ : java
Using javac ............... : javac
Using Gradle version ...... : Gradle 8.14.3
Using java version ........ : openjdk version "11.0.28" 2025-07-15
为了便于cmake动态找到thrift地址,确认/home/gaoyong/soft/thrift/lib/pkgconfig已经有了相应的文件
# 如果没有对应的thrift配置文件,创建
sudo mkdir -p /home/gaoyong/soft/thrift/lib/pkgconfig
sudo tee /home/gaoyong/soft/thrift/lib/pkgconfiglibthrift.pc <<EOF
prefix=/home/gaoyong/soft/thrift/
exec_prefix=${prefix}
libdir=${exec_prefix}/lib
includedir=${prefix}/include
Name: Thrift
Description: Thrift C++ Library
Version: 0.22.0
Libs: -L${libdir} -lthrift
Cflags: -I${includedir}
EOF
# 如果有,设置路径
echo 'export PKG_CONFIG_PATH=/home/gaoyong/soft/thrift/lib/pkgconfig:$PKG_CONFIG_PATH' >> ~/.bashrc
source ~/.bashrc
# 验证这些指令是否正常,cmake依赖其定位thrift路径
pkg-config --modversion thrift
# 检查编译和链接参数
echo "头文件参数: $(pkg-config --cflags thrift)"
echo "库链接参数: $(pkg-config --libs thrift)"构建成功之后,可通过make install安装,默认不会安装java的jar包到目标目录。另外python基于其兼容旧版本的考虑,默认放到了固定目录,prefix无效(这里我禁用了python,实际比较友好)。将java包手工拷贝之后,可在目标安装目录看到如下结构:
:~/soft/thrift$ tree
.
├── bin
│ └── thrift
├── include
│ └── thrift
│ ├── async
│ │ ├── TAsyncBufferProcessor.h
│ │ ├── TAsyncChannel.h
│ │ ├── TAsyncDispatchProcessor.h
│ │ ├── TAsyncProcessor.h
│ │ ├── TAsyncProtocolProcessor.h
│ │ ├── TConcurrentClientSyncInfo.h
│ │ ├── TEvhttpClientChannel.h
│ │ └── TEvhttpServer.h
│ ├── c_glib
│ │ ├── config.h
│ │ ├── processor
│ │ │ ├── thrift_dispatch_processor.h
│ │ │ ├── thrift_multiplexed_processor.h
│ │ │ └── thrift_processor.h
│ │ ├── protocol
│ │ │ ├── thrift_binary_protocol_factory.h
│ │ │ ├── thrift_binary_protocol.h
│ │ │ ├── thrift_compact_protocol_factory.h
│ │ │ ├── thrift_compact_protocol.h
│ │ │ ├── thrift_multiplexed_protocol.h
│ │ │ ├── thrift_protocol_decorator.h
│ │ │ ├── thrift_protocol_factory.h
│ │ │ ├── thrift_protocol.h
│ │ │ └── thrift_stored_message_protocol.h
│ │ ├── server
│ │ │ ├── thrift_server.h
│ │ │ └── thrift_simple_server.h
│ │ ├── thrift_application_exception.h
│ │ ├── thrift_configuration.h
│ │ ├── thrift.h
│ │ ├── thrift_struct.h
│ │ └── transport
│ │ ├── thrift_buffered_transport_factory.h
│ │ ├── thrift_buffered_transport.h
│ │ ├── thrift_fd_transport.h
│ │ ├── thrift_framed_transport_factory.h
│ │ ├── thrift_framed_transport.h
│ │ ├── thrift_memory_buffer.h
│ │ ├── thrift_platform_socket.h
│ │ ├── thrift_server_socket.h
│ │ ├── thrift_server_transport.h
│ │ ├── thrift_socket.h
│ │ ├── thrift_ssl_socket.h
│ │ ├── thrift_transport_factory.h
│ │ ├── thrift_transport.h
│ │ ├── thrift_zlib_transport_factory.h
│ │ └── thrift_zlib_transport.h
│ ├── concurrency
│ │ ├── Exception.h
│ │ ├── FunctionRunner.h
│ │ ├── Monitor.h
│ │ ├── Mutex.h
│ │ ├── ThreadFactory.h
│ │ ├── Thread.h
│ │ ├── ThreadManager.h
│ │ └── TimerManager.h
│ ├── config.h
│ ├── processor
│ │ ├── PeekProcessor.h
│ │ ├── StatsProcessor.h
│ │ └── TMultiplexedProcessor.h
│ ├── protocol
│ │ ├── TBase64Utils.h
│ │ ├── TBinaryProtocol.h
│ │ ├── TBinaryProtocol.tcc
│ │ ├── TCompactProtocol.h
│ │ ├── TCompactProtocol.tcc
│ │ ├── TDebugProtocol.h
│ │ ├── TEnum.h
│ │ ├── THeaderProtocol.h
│ │ ├── TJSONProtocol.h
│ │ ├── TList.h
│ │ ├── TMap.h
│ │ ├── TMultiplexedProtocol.h
│ │ ├── TProtocolDecorator.h
│ │ ├── TProtocolException.h
│ │ ├── TProtocol.h
│ │ ├── TProtocolTap.h
│ │ ├── TProtocolTypes.h
│ │ ├── TSet.h
│ │ └── TVirtualProtocol.h
│ ├── qt
│ │ ├── TQIODeviceTransport.h
│ │ └── TQTcpServer.h
│ ├── server
│ │ ├── TConnectedClient.h
│ │ ├── TNonblockingServer.h
│ │ ├── TServerFramework.h
│ │ ├── TServer.h
│ │ ├── TSimpleServer.h
│ │ ├── TThreadedServer.h
│ │ └── TThreadPoolServer.h
│ ├── TApplicationException.h
│ ├── TBase.h
│ ├── TConfiguration.h
│ ├── TDispatchProcessor.h
│ ├── thrift-config.h
│ ├── thrift_export.h
│ ├── Thrift.h
│ ├── TLogging.h
│ ├── TNonCopyable.h
│ ├── TOutput.h
│ ├── TProcessor.h
│ ├── transport
│ │ ├── PlatformSocket.h
│ │ ├── SocketCommon.h
│ │ ├── TBufferTransports.h
│ │ ├── TFDTransport.h
│ │ ├── TFileTransport.h
│ │ ├── THeaderTransport.h
│ │ ├── THttpClient.h
│ │ ├── THttpServer.h
│ │ ├── THttpTransport.h
│ │ ├── TNonblockingServerSocket.h
│ │ ├── TNonblockingServerTransport.h
│ │ ├── TNonblockingSSLServerSocket.h
│ │ ├── TPipe.h
│ │ ├── TPipeServer.h
│ │ ├── TServerSocket.h
│ │ ├── TServerTransport.h
│ │ ├── TShortReadTransport.h
│ │ ├── TSimpleFileTransport.h
│ │ ├── TSocket.h
│ │ ├── TSocketPool.h
│ │ ├── TSocketUtils.h
│ │ ├── TSSLServerSocket.h
│ │ ├── TSSLSocket.h
│ │ ├── TTransportException.h
│ │ ├── TTransport.h
│ │ ├── TTransportUtils.h
│ │ ├── TVirtualTransport.h
│ │ ├── TWebSocketServer.h
│ │ └── TZlibTransport.h
│ ├── TToString.h
│ └── TUuid.h
└── lib
├── libthrift-0.22.0.jar
├── libthrift-0.22.0-javadoc.jar
├── libthrift-0.22.0-SNAPSHOT.jar
├── libthrift-0.22.0.so
├── libthrift-0.22.0-sources.jar
├── libthrift.a
├── libthrift_c_glib.a
├── libthrift_c_glib.la
├── libthrift_c_glib.so -> libthrift_c_glib.so.0.0.0
├── libthrift_c_glib.so.0 -> libthrift_c_glib.so.0.0.0
├── libthrift_c_glib.so.0.0.0
├── libthrift.la
├── libthriftnb-0.22.0.so
├── libthriftnb.a
├── libthriftnb.la
├── libthriftnb.so -> libthriftnb-0.22.0.so
├── libthrift.so -> libthrift-0.22.0.so
├── libthriftz-0.22.0.so
├── libthriftz.a
├── libthriftz.la
├── libthriftz.so -> libthriftz-0.22.0.so
└── pkgconfig
├── libthrift.pc
├── thrift_c_glib.pc
├── thrift-nb.pc
├── thrift.pc
└── thrift-z.pc
基于C++开发服务与客户端
编写IDL
下面是一个名字为echo.thrift的接口定义文件
namespace cpp echo
namespace java com.example.echo
service EchoService {
string echo(1:string message)
i32 add(2:i32 a, 3:i32 b)
}
用IDL生成C++代码
$ thrift gen-cpp -o ./target_dir/echo.thrift
$ tree ./target_dir
.
├── EchoService.cpp
├── EchoService.h
├── EchoService_server.skeleton.cpp
└── echo_types.h
实现服务端
服务端重点参考EchoService.h文件中的关于接口的虚基类,如下
...
class EchoServiceIf {
public:
virtual ~EchoServiceIf() {}
virtual void echo(std::string& _return, const std::string& message) = 0;
virtual int32_t add(const int32_t a, const int32_t b) = 0;
};
...完整服务端的代码如下:
// cat src/cpp/EchoServer.cpp
#include <thrift/transport/TSocket.h>
#include <thrift/transport/TBufferTransports.h>
#include <thrift/protocol/TBinaryProtocol.h>
#include <thrift/server/TSimpleServer.h>
#include <thrift/transport/TServerSocket.h>
#include <thrift/transport/TTransportUtils.h>
#include <iostream>
#include <stdexcept>
#include <sstream>
// 包含生成的代码
#include "gen-cpp/EchoService.h"
using namespace std;
using namespace apache::thrift;
using namespace apache::thrift::protocol;
using namespace apache::thrift::transport;
using namespace apache::thrift::server;
using namespace echo;
// 实现EchoService接口
class EchoServiceHandler : virtual public EchoServiceIf {
public:
EchoServiceHandler() {
// 初始化代码(如果需要)
}
// echo方法:通过引用参数返回字符串(Thrift生成的签名要求)
void echo(std::string& _return, const string& message) {
cout << "收到echo请求: " << message << endl;
_return = message; // 通过引用返回结果
}
// add方法:直接返回int32_t(根据当前生成的代码签名调整)
int32_t add(const int32_t a, const int32_t b) {
cout << "收到add请求: " << a << " + " << b << endl;
return a + b; // 直接返回计算结果
}
};
int main(int argc, char **argv) {
int port = 9090; // 服务端口
// 创建处理器
shared_ptr<EchoServiceHandler> handler(new EchoServiceHandler());
shared_ptr<TProcessor> processor(new EchoServiceProcessor(handler));
// 设置服务端口
shared_ptr<TServerTransport> serverTransport(new TServerSocket(port));
shared_ptr<TTransportFactory> transportFactory(new TBufferedTransportFactory());
shared_ptr<TProtocolFactory> protocolFactory(new TBinaryProtocolFactory());
// 创建并启动服务器
TSimpleServer server(processor, serverTransport, transportFactory, protocolFactory);
cout << "Echo服务已启动,监听端口 " << port << endl;
server.serve();
return 0;
}
实现客户端
客户端关注EchoService.h的方法,不过关注的是如何使用,另外注意使用的是文件中定义的EchoServiceClient类。完整的客户端代码如下:
// cat src/cpp/EchoClient.cpp
#include <thrift/transport/TSocket.h>
#include <thrift/transport/TBufferTransports.h>
#include <thrift/protocol/TBinaryProtocol.h>
#include <iostream>
// 包含生成的代码
#include "gen-cpp/EchoService.h"
using namespace std;
using namespace apache::thrift;
using namespace apache::thrift::protocol;
using namespace apache::thrift::transport;
using namespace echo;
int main(int argc, char **argv) {
string host = "localhost";
int port = 9090;
// 创建传输和协议
shared_ptr<TTransport> socket(new TSocket(host, port));
shared_ptr<TTransport> transport(new TBufferedTransport(socket));
shared_ptr<TProtocol> protocol(new TBinaryProtocol(transport));
// 创建客户端
EchoServiceClient client(protocol);
try {
// 连接到服务器
transport->open();
// 调用echo方法
string echo_response;
client.echo(echo_response,"Hello from C++ client!");
cout << "echo响应: " << echo_response << endl;
// 调用add方法
int32_t add_response = client.add(10, 20);
cout << "add响应: 10 + 20 = " << add_response << endl;
// 关闭连接
transport->close();
} catch (TException& tx) {
cerr << "Thrift异常: " << tx.what() << endl;
}
return 0;
}
使用cmake构建
这里示范一个简单的工程,相应目录结构如下:
├── CMakeLists.txt
├── readme.md
└── src
├── cpp
│ ├── EchoClient.cpp
│ └── EchoServer.cpp
└── idl
└── echo.thrift
在这样的文件结果下,CMakeLists.txt的内容如下:
cmake_minimum_required(VERSION 3.10)
project(EchoProject)
# 设置构建类型
if(NOT CMAKE_BUILD_TYPE)
set(CMAKE_BUILD_TYPE Release)
endif()
# 查找Thrift编译器
find_program(THRIFT_COMPILER thrift)
if(NOT THRIFT_COMPILER)
message(FATAL_ERROR "Thrift compiler not found! Please install thrift.")
endif()
# 查找Thrift C++库
find_package(PkgConfig REQUIRED)
pkg_check_modules(THRIFT REQUIRED thrift)
# 添加 Thrift 库的搜索路径(关键步骤)
link_directories(${THRIFT_LIBRARY_DIRS})
# 查找Java
find_package(Java COMPONENTS Runtime REQUIRED)
# 设置Thrift文件路径
set(THRIFT_FILE ${CMAKE_CURRENT_SOURCE_DIR}/src/idl/echo.thrift)
# 设置生成代码的目录
set(CPP_GEN_DIR ${CMAKE_BINARY_DIR}/gen-cpp)
# 确保生成目录存在
file(MAKE_DIRECTORY ${CPP_GEN_DIR})
# 定义Thrift生成的文件(基于命名约定)
set(THRIFT_GEN_CPP_FILES
${CPP_GEN_DIR}/EchoService.cpp
)
# 阶段1: 生成C++ Thrift代码
add_custom_command(
OUTPUT ${THRIFT_GEN_CPP_FILES}
COMMAND ${THRIFT_COMPILER} --gen cpp -o ${CMAKE_BINARY_DIR} ${THRIFT_FILE}
DEPENDS ${THRIFT_FILE}
COMMENT "阶段1: 生成C++ Thrift代码"
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
)
# 创建自定义目标来触发代码生成
add_custom_target(generate_thrift_cpp DEPENDS ${THRIFT_GEN_CPP_FILES})
# 阶段2: 构建EchoServer(包含生成的Thrift文件)
add_executable(EchoServer
src/cpp/EchoServer.cpp
${THRIFT_GEN_CPP_FILES} # 直接包含生成的源文件
)
target_include_directories(EchoServer PRIVATE
${CMAKE_BINARY_DIR}
${CPP_GEN_DIR}
${THRIFT_INCLUDE_DIRS}
)
target_link_libraries(EchoServer ${THRIFT_LIBRARIES} pthread)
# 确保Thrift代码先生成
add_dependencies(EchoServer generate_thrift_cpp)
# 阶段3: 构建EchoClient(包含生成的Thrift文件)
add_executable(EchoClient
src/cpp/EchoClient.cpp
${THRIFT_GEN_CPP_FILES} # 直接包含生成的源文件
)
target_include_directories(EchoClient PRIVATE
${CMAKE_BINARY_DIR}
${CPP_GEN_DIR}
${THRIFT_INCLUDE_DIRS}
)
target_link_libraries(EchoClient ${THRIFT_LIBRARIES} pthread)
# 确保Thrift代码先生成
add_dependencies(EchoClient generate_thrift_cpp)
# 为每个阶段创建别名,方便单独调用
add_custom_target(gen_cpp DEPENDS generate_thrift_cpp)
add_custom_target(build_server DEPENDS EchoServer)
add_custom_target(build_client DEPENDS EchoClient)
# 构建所有目标
add_custom_target(cpp_all
DEPENDS EchoServer EchoClient
COMMENT "构建所有目标"
)
# 默认目标
add_custom_target(default ALL DEPENDS cpp_all)
# 显示构建信息
message(STATUS "构建类型: ${CMAKE_BUILD_TYPE}")
message(STATUS "Thrift编译器: ${THRIFT_COMPILER}")
message(STATUS "Thrift包含目录: ${THRIFT_INCLUDE_DIRS}")
message(STATUS "Thrift库: ${THRIFT_LIBRARIES}")
执行构建的步骤如下:
# 生成Ninja构建
cmake -S . -B build -G Ninja
# 执行构建 :如下两个指令等价
cmake --build build/
pushd build ; ninja; popd
# 清空构建
cmake --build build/ --target clean
pushd build ; ninja clean; popd测试
./build/EchoServer &
./build/EchoClient
# 测试完毕,干掉Server
killall EchoServer
$ time build/EchoClient 127.0.0.1
echo响应: Hello from C++ client!
add响应: 10 + 20 = 30
real 0m0.004s
user 0m0.002s
sys 0m0.002s
$ time ./build/EchoClient 172.21.168.128 9090
echo响应: Hello from C++ client!
add响应: 10 + 20 = 30
real 0m0.005s
user 0m0.002s
sys 0m0.001s
基于Java开发客户端
原则上Java想调用Thrift编写的服务,只需要获得IDL文件即可。其他可以通过同样版本的Thrift获得。
JDK
需要准备准备好JDK11,以及gradle环境。如果装了多个java需要切换可参考如下维度选择:
# 系统级别 : 但是优先级会被后面的覆盖
sudo update-alternatives --config java
# 环境变量 : 比较灵活,影响用户会话阶段,通过.bashrc实现持久
export JAVA_HOME=
export PATH=$JAVA_HOME/bin:$PATH
# 工程设定 : 例如gradle
org.gradle.java.home=/usr/lib/jvm/java-17-openjdk-amd64
# SDKMAN辅助
类似pyenv之类的用来管理jdk版本的,适合开发者有多重版本不断切换的诉求sudo apt install openjdk-11-jdkgradle
可以从官网获得gradle对应的安装包,然后自行解压到特定目录,一般建议为~/.gradle/wrapper/dists/gradle-8.14.3-bin/cv11ve7ro1n3o1j4so8xd9n66/gradle-8.14.3/bin/,然后配置到PATH能量。
# 可以直接使用gradle build 开始构建,一般都会通过如下命令生成一个gradlew
gradle wrapper
./gradlew build实现客户端
可以通过命令从IDL获得java代码,代码很长,但是客户端引用后,只要按照规则使用这块代码。
$thrift --gen java -o ./j/ src/main/thrift/echo.thrift
$tree j
j
└── gen-java
└── com
└── example
└── echo
└── EchoService.java
客户端的完整代码如下:
package com.example.echo;
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;
// 导入生成的Java代码
import com.example.echo.EchoService;
public class EchoClient {
public static void main(String[] args) {
// 默认连接参数
String host = args.length > 0 ? args[0] : "localhost";
int port = args.length > 1 ? Integer.parseInt(args[1]) : 9090;
TTransport transport = null;
try {
// 创建传输
transport = new TSocket(host, port);
// 打开连接
transport.open();
// 创建协议
TProtocol protocol = new TBinaryProtocol(transport);
// 创建客户端
EchoService.Client client = new EchoService.Client(protocol);
// 调用echo方法
String echoResponse = client.echo("Hello from Java client!");
System.out.println("echo响应: " + echoResponse);
// 调用add方法
int addResponse = client.add(30, 40);
System.out.println("add响应: 30 + 40 = " + addResponse);
} catch (TTransportException e) {
System.err.println("传输层错误: " + e.getMessage());
e.printStackTrace();
} catch (TException e) {
System.err.println("Thrift调用错误: " + e.getMessage());
e.printStackTrace();
} catch (Exception e) {
System.err.println("未知错误: " + e.getMessage());
e.printStackTrace();
} finally {
// 确保连接被关闭
if (transport != null) {
transport.close();
}
}
}
}
只需要特别关注下通过EchoService.Client client = new EchoService.Client(protocol);获得对象, 其他与在IDL中一样。
工程目录
这里演示一个极简单的工程目录,演示通过gradle构建Java客户端。
tree
.
├── build.gradle
├── lib
├── settings.gradle
└── src
└── main
├── java
│ └── com
│ └── example
│ └── echo
│ └── EchoClient.java
└── thrift
└── echo.thrift
上述目录下的build.gradle内容如下:
plugins {
id 'java'
}
// 严格离线模式:仅使用本地lib/目录
repositories {
// 优先查找本地 lib/ 目录
flatDir {
dirs 'lib'
content {
// 仅在本地找不到时,才允许从远程下载
excludeGroupByRegex '.*' // 强制优先使用本地文件
}
}
// 本地找不到时,从远程仓库下载
mavenCentral()
}
dependencies {
// 本地依赖(如果存在)
implementation fileTree(dir: 'lib', include: '*.jar')
// 远程依赖(本地不存在时下载)
implementation 'com.google.code.findbugs:jsr305:3.0.2'
implementation 'org.slf4j:slf4j-api:1.7.36'
implementation 'ch.qos.logback:logback-classic:1.2.11'
implementation 'org.apache.thrift:libthrift:0.22.0'
implementation 'com.google.code.findbugs:jsr305:3.0.2' // 提供 javax.annotation
implementation 'javax.annotation:javax.annotation-api:1.3.2'
}
// 生成代码时禁用注解(关键!)
task generateThrift(type: Exec) {
commandLine '/home/gaoyong/soft/thrift/bin/thrift',
'--gen', 'java',
'-o', "${projectDir}/build/generated-sources",
"${projectDir}/src/main/thrift/echo.thrift"
doFirst { mkdir 'build/generated-sources' }
}
// 将生成的代码加入编译
sourceSets.main.java.srcDirs += 'build/generated-sources/gen-java'
compileJava.dependsOn generateThrift
// 打包可执行JAR(包含所有依赖)
jar {
manifest {
attributes(
'Main-Class': 'com.example.echo.EchoClient',
'Class-Path': configurations.runtimeClasspath.files.collect { it.name }.join(' ')
)
}
from {
configurations.runtimeClasspath.collect {
it.isDirectory() ? it : zipTree(it)
}
}
duplicatesStrategy = DuplicatesStrategy.EXCLUDE
archiveFileName = "echo-client.jar"
}
// 添加运行任务(可选)
task runClient(type: JavaExec) {
classpath = sourceSets.main.runtimeClasspath
mainClass = 'com.example.echo.EchoClient'
args = ['localhost', '9090'] // 默认参数
}
构建
# 基于全局的gradle直接构建和清除
gradle build
gradle clean
# 按照常规生成gradlew的方式
gradle wrapper
./gradlew build
./gradlew clean测试
$ java -jar build/libs/echo-client.jar
echo响应: Hello from Java client!
add响应: 30 + 40 = 70
$ time java -jar build/libs/echo-client.jar
echo响应: Hello from Java client!
add响应: 30 + 40 = 70
real 0m0.119s
user 0m0.171s
sys 0m0.034s
$ time java -jar build/libs/echo-client.jar 172.21.168.128
echo响应: Hello from Java client!
add响应: 30 + 40 = 70
real 0m0.210s
user 0m0.162s
sys 0m0.019s
异常
对python,指定的prefix无效,这里看起来应该结合python的运行机制来调整,这里通过屏蔽python先搁置
# We're ignoring prefix here because site-packages seems to be
# the equivalent of /usr/local/lib in Python land.
# Old version (can't put inline because it's not portable).
#$(PYTHON) setup.py install --prefix=$(prefix) --root=$(DESTDIR) $(PYTHON_SETUPUTIL_ARGS)
install-exec-hook:
$(PYTHON) -m pip install . --root=$(DESTDIR) --prefix=$(PY_PREFIX) $(PYTHON_SETUPUTIL_ARGS)
参考资料
Thrift的IDL https://thrift.apache.org/docs/idl.html
Gradle https://gradle.org/