Swift:Thrift Java注解支持
Posted Future的博客
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Swift:Thrift Java注解支持相关的知识,希望对你有一定的参考价值。
Swift is an easy-to-use, annotation-based Java library for creating Thrift serializable types and services.
Facebook开源了Thrift相关的其他两个项目: Nifty 和 Swift ; 对于纯Java应用开发者来说,相对于编写Thrift IDL,我们可能更倾向于写Java Bean或者Service,Swift项目提供了Thrift Java注解支持,提高了开发效率;
Swift使用示例
下面以ThirdPartyCollectionService.thrift为例,编写完IDL文件还需要编译生成Java代码导入到项目中:
struct ThirdPartyCollection {
1: required i32 id;
2: optional string data;
}
service ThirdPartyCollectionService {
string save(1: ThirdPartyCollection collection)
}
假如使用Swift注解,只需要在对应的Java Bean和Service打上相应的注解即可(具体的使用方法请参考官方文档)。参考如下:
@ThriftStruct
public final class ThirdPartyCollection {
public final long id; // required
public final String date; // optional
@ThriftConstructor
public ThirdPartyCollection(long id, String date) {
this.id = id;
this.date = date;
}
@ThriftField(1)
public long getId() {
return id;
}
@ThriftField(2)
public String getDate() {
return date;
}
}
@ThriftService("ThirdPartyCollectionService")
public interface ThirdPartyCollectionService {
@ThriftMethod
String save(@ThriftField(name = "collection") ThirdPartyCollection collection);
}
那么具体怎么使用Swift来编写RPC的Client和Server呢(其实Swift底层依赖了Nifty,扩展了Nifty来支持RPC调用),具体参考如下:
引入POM依赖
<dependency>
<groupId>com.facebook.swift</groupId>
<artifactId>swift-service</artifactId>
<version>0.18.0</version>
</dependency>
RPC Server
public class ThirdPartyCollectionServiceImpl implements ThirdPartyCollectionService {
public String save(@ThriftField(name = "collection") ThirdPartyCollection collection) {
System.out.println(collection.toString());
return "Success";
}
}
public class ServerDemo {
public static void main(String[] args) throws IOException, InterruptedException {
ThriftServiceProcessor processor = new ThriftServiceProcessor(
new ThriftCodecManager(),
ImmutableList.<ThriftEventHandler>of(),
new ThirdPartyCollectionServiceImpl()
);
ExecutorService taskWorkerExecutor = Executors.newFixedThreadPool(1);
ThriftServerDef serverDef = ThriftServerDef.newBuilder()
.listen(8899)
.withProcessor(processor)
.using(taskWorkerExecutor)
.build();
ExecutorService bossExecutor = Executors.newCachedThreadPool();
ExecutorService ioWorkerExecutor = Executors.newCachedThreadPool();
NettyServerConfig serverConfig = NettyServerConfig.newBuilder()
.setBossThreadExecutor(bossExecutor)
.setWorkerThreadExecutor(ioWorkerExecutor)
.build();
ThriftServer server = new ThriftServer(serverConfig, serverDef);
server.start();
}
}
RPC Client
public class ClientDemo {
public static void main(String[] args) throws ExecutionException, InterruptedException {
ThriftClientManager clientManager = new ThriftClientManager();
FramedClientConnector connector = new FramedClientConnector(new InetSocketAddress("localhost",8899));
ThirdPartyCollectionService service = clientManager.createClient(connector, ThirdPartyCollectionService.class).get();
String result = service.save(new ThirdPartyCollection(1001, "2014-08-29"));
System.out.println(result);
}
}
Swift进阶
有些RPC中间件基于Thrift进行了二次开发,那此时怎么在自己的组件里支持Thrift注解呢? 首先引入swift-service依赖,改写ThriftMethodHandler和ThriftMethodProcessor两个类即可; 下面是用Swift模拟Client发送消息,Server接受消息处理并返回的关键代码:
public class SerializeTest {
private static final AtomicInteger sequenceId = new AtomicInteger(1);
private static Map<Method, ThriftMethodHandler> thriftMethodHandlerMap;
private static Map<String, ThriftMethodProcessor> thriftMethodProcessorMap;
public static void main(String[] args) throws Throwable {
Class clazz = Class.forName("com.example.gs.ThirdPartyCollectionService");
Object service = new ThirdPartyCollectionServiceImpl();
Object arg = new ThirdPartyCollection(1001, "2014-08-29");
//初始化
thriftMethodHandlerMap = createThriftMethodHandlerMap(clazz);
thriftMethodProcessorMap = createThriftMethodProcessorMap(clazz, service);
//调用ThirdPartyCollectionService的save方法
Method method = clazz.getMethod("save", ThirdPartyCollection.class);
ThriftMethodHandler methodHandler = thriftMethodHandlerMap.get(method);
byte[] data;
data = clientSend(methodHandler, arg);
data = serverProcess(data);
Object result = clientReceive(data, methodHandler);
System.out.println("Response:" + result);
}
/**
* 创建client用到的ThriftMethodHandler
* @return
*/
public static Map<Method, ThriftMethodHandler> createThriftMethodHandlerMap(Class clazz) {
ThriftCodecManager codecManager = new ThriftCodecManager();
ThriftServiceMetadata thriftServiceMetadata = new ThriftServiceMetadata(clazz, codecManager.getCatalog());
ImmutableMap.Builder<Method, ThriftMethodHandler> methods = ImmutableMap.builder();
for (ThriftMethodMetadata methodMetadata : thriftServiceMetadata.getMethods().values()) {
ThriftMethodHandler thriftMethodHandler = new ThriftMethodHandler(methodMetadata, codecManager);
methods.put(methodMetadata.getMethod(), thriftMethodHandler);
}
Map<Method, ThriftMethodHandler> thriftMethodHandlerMap = methods.build();
return thriftMethodHandlerMap;
}
/**
* 创建server用到的ThriftMethodProcessor
* @return
*/
public static Map<String, ThriftMethodProcessor> createThriftMethodProcessorMap(Class clazz, Object service) {
ThriftCodecManager codecManager = new ThriftCodecManager();
ThriftServiceMetadata thriftServiceMetadata = new ThriftServiceMetadata(clazz, codecManager.getCatalog());
Map<String, ThriftMethodProcessor> processorMap = newHashMap();
for (ThriftMethodMetadata methodMetadata : thriftServiceMetadata.getMethods().values()) {
String methodName = methodMetadata.getName();
ThriftMethodProcessor methodProcessor = new ThriftMethodProcessor(service, thriftServiceMetadata.getName(), methodMetadata, codecManager);
if (processorMap.containsKey(methodName)) {
throw new IllegalArgumentException("Multiple @ThriftMethod-annotated methods named '" + methodName + "' found in the given services");
}
processorMap.put(methodName, methodProcessor);
}
Map<String, ThriftMethodProcessor> thriftMethodProcessorMap = ImmutableMap.copyOf(processorMap);
return thriftMethodProcessorMap;
}
public static byte[] clientSend(ThriftMethodHandler methodHandler, Object... args) {
ByteArrayOutputStream out = new ByteArrayOutputStream(1024);
TiostreamTransport transport = new TIOStreamTransport(out);
TProtocol outProtocol = new TBinaryProtocol.Factory().getProtocol(transport);
try {
methodHandler.send(outProtocol, sequenceId.getAndIncrement(), args);
} catch (Exception e) {
e.printStackTrace();
}
return out.toByteArray();
}
public static byte[] serverProcess(byte[] data) {
TProtocol in = new TBinaryProtocol.Factory().getProtocol(new TIOStreamTransport(new ByteArrayInputStream(data)));
TMessage message = null;
try {
message = in.readMessageBegin();
} catch (TException e) {
e.printStackTrace();
}
int sequenceId = message.seqid;
String methodName = message.name;
ThriftMethodProcessor methodProcessor = thriftMethodProcessorMap.get(methodName);
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(1024);
TIOStreamTransport transport = new TIOStreamTransport(byteArrayOutputStream);
TProtocol out = new TBinaryProtocol.Factory().getProtocol(transport);
try {
methodProcessor.process(in, out, sequenceId);
} catch (Throwable t) {
t.printStackTrace();
}
return byteArrayOutputStream.toByteArray();
}
public static Object clientReceive(byte[] data, ThriftMethodHandler methodHandler) {
TProtocol in = new TBinaryProtocol.Factory().getProtocol(new TIOStreamTransport(new ByteArrayInputStream(data)));
Object result = null;
try {
result = methodHandler.receive(in, sequenceId.get() - 1);
} catch (Exception e) {
e.printStackTrace();
}
return result;
}
}
此外还有一点需要说明的是,swift-service依赖jdk8,如果自己的RPC组件暂不能升级到jdk8,那该怎么办呢? 其实也很简单,只需要引入swift-codec和swift-annotations两个依赖(无需引入swift-service),同时把swift-service中的ThriftMethodMetadata和ThriftServiceMetadata拷贝到自己的项目里面,这样就可以不用升级jdk8也能使用Swift提供的注解功能; Swift本身还有很多组件,比如swift-idl-parser、swift-generator等,感兴趣的读者可以参考官方文档继续深入学习! 本文完整示例代码可参考:https://github.com/gaosheng/ThriftWithSwiftDemo
以上是关于Swift:Thrift Java注解支持的主要内容,如果未能解决你的问题,请参考以下文章