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代码导入到项目中:

 
   
   
 
  1. struct ThirdPartyCollection {

  2.    1: required i32 id;

  3.    2: optional string data;

  4. }

  5. service ThirdPartyCollectionService {

  6.    string save(1: ThirdPartyCollection collection)

  7. }

假如使用Swift注解,只需要在对应的Java Bean和Service打上相应的注解即可(具体的使用方法请参考官方文档)。参考如下:

 
   
   
 
  1. @ThriftStruct

  2. public final class ThirdPartyCollection {

  3.    public final long id; // required

  4.    public final String date; // optional

  5.    @ThriftConstructor

  6.    public ThirdPartyCollection(long id, String date) {

  7.        this.id = id;

  8.        this.date = date;

  9.    }

  10.    @ThriftField(1)

  11.    public long getId() {

  12.        return id;

  13.    }

  14.    @ThriftField(2)

  15.    public String getDate() {

  16.        return date;

  17.    }

  18. }

  19. @ThriftService("ThirdPartyCollectionService")

  20. public interface ThirdPartyCollectionService {

  21.    @ThriftMethod

  22.    String save(@ThriftField(name = "collection") ThirdPartyCollection collection);

  23. }

那么具体怎么使用Swift来编写RPC的Client和Server呢(其实Swift底层依赖了Nifty,扩展了Nifty来支持RPC调用),具体参考如下:

引入POM依赖

 
   
   
 
  1. <dependency>

  2.    <groupId>com.facebook.swift</groupId>

  3.    <artifactId>swift-service</artifactId>

  4.    <version>0.18.0</version>

  5. </dependency>

RPC Server

 
   
   
 
  1. public class ThirdPartyCollectionServiceImpl implements ThirdPartyCollectionService {

  2.    public String save(@ThriftField(name = "collection") ThirdPartyCollection collection) {

  3.        System.out.println(collection.toString());

  4.        return "Success";

  5.    }

  6. }

  7. public class ServerDemo {

  8.    public static void main(String[] args) throws IOException, InterruptedException {

  9.        ThriftServiceProcessor processor = new ThriftServiceProcessor(

  10.                new ThriftCodecManager(),

  11.                ImmutableList.<ThriftEventHandler>of(),

  12.                new ThirdPartyCollectionServiceImpl()

  13.        );

  14.        ExecutorService taskWorkerExecutor = Executors.newFixedThreadPool(1);

  15.        ThriftServerDef serverDef = ThriftServerDef.newBuilder()

  16.                .listen(8899)

  17.                .withProcessor(processor)

  18.                .using(taskWorkerExecutor)

  19.                .build();

  20.        ExecutorService bossExecutor = Executors.newCachedThreadPool();

  21.        ExecutorService ioWorkerExecutor = Executors.newCachedThreadPool();

  22.        NettyServerConfig serverConfig = NettyServerConfig.newBuilder()

  23.                .setBossThreadExecutor(bossExecutor)

  24.                .setWorkerThreadExecutor(ioWorkerExecutor)

  25.                .build();

  26.        ThriftServer server = new ThriftServer(serverConfig, serverDef);

  27.        server.start();

  28.    }

  29. }

RPC Client

 
   
   
 
  1. public class ClientDemo {

  2.    public static void main(String[] args) throws ExecutionException, InterruptedException {

  3.        ThriftClientManager clientManager = new ThriftClientManager();

  4.        FramedClientConnector connector = new FramedClientConnector(new InetSocketAddress("localhost",8899));

  5.        ThirdPartyCollectionService service = clientManager.createClient(connector, ThirdPartyCollectionService.class).get();

  6.        String result = service.save(new ThirdPartyCollection(1001, "2014-08-29"));

  7.        System.out.println(result);

  8.    }

  9. }

Swift进阶

有些RPC中间件基于Thrift进行了二次开发,那此时怎么在自己的组件里支持Thrift注解呢? 首先引入swift-service依赖,改写ThriftMethodHandler和ThriftMethodProcessor两个类即可; 下面是用Swift模拟Client发送消息,Server接受消息处理并返回的关键代码:

 
   
   
 
  1. public class SerializeTest {

  2.    private static final AtomicInteger sequenceId = new AtomicInteger(1);

  3.    private static Map<Method, ThriftMethodHandler> thriftMethodHandlerMap;

  4.    private static Map<String, ThriftMethodProcessor> thriftMethodProcessorMap;

  5.    public static void main(String[] args) throws Throwable {

  6.        Class clazz = Class.forName("com.example.gs.ThirdPartyCollectionService");

  7.        Object service = new ThirdPartyCollectionServiceImpl();

  8.        Object arg = new ThirdPartyCollection(1001, "2014-08-29");

  9.        //初始化

  10.        thriftMethodHandlerMap = createThriftMethodHandlerMap(clazz);

  11.        thriftMethodProcessorMap = createThriftMethodProcessorMap(clazz, service);

  12.        //调用ThirdPartyCollectionService的save方法

  13.        Method method = clazz.getMethod("save", ThirdPartyCollection.class);

  14.        ThriftMethodHandler methodHandler = thriftMethodHandlerMap.get(method);

  15.        byte[] data;

  16.        data = clientSend(methodHandler, arg);

  17.        data = serverProcess(data);

  18.        Object result = clientReceive(data, methodHandler);

  19.        System.out.println("Response:" + result);

  20.    }

  21.    /**

  22.     * 创建client用到的ThriftMethodHandler

  23.     * @return

  24.     */

  25.    public static Map<Method, ThriftMethodHandler> createThriftMethodHandlerMap(Class clazz) {

  26.        ThriftCodecManager codecManager = new ThriftCodecManager();

  27.        ThriftServiceMetadata thriftServiceMetadata = new ThriftServiceMetadata(clazz, codecManager.getCatalog());

  28.        ImmutableMap.Builder<Method, ThriftMethodHandler> methods = ImmutableMap.builder();

  29.        for (ThriftMethodMetadata methodMetadata : thriftServiceMetadata.getMethods().values()) {

  30.            ThriftMethodHandler thriftMethodHandler = new ThriftMethodHandler(methodMetadata, codecManager);

  31.            methods.put(methodMetadata.getMethod(), thriftMethodHandler);

  32.        }

  33.        Map<Method, ThriftMethodHandler> thriftMethodHandlerMap = methods.build();

  34.        return thriftMethodHandlerMap;

  35.    }

  36.    /**

  37.     * 创建server用到的ThriftMethodProcessor

  38.     * @return

  39.     */

  40.    public static Map<String, ThriftMethodProcessor> createThriftMethodProcessorMap(Class clazz, Object service) {

  41.        ThriftCodecManager codecManager = new ThriftCodecManager();

  42.        ThriftServiceMetadata thriftServiceMetadata = new ThriftServiceMetadata(clazz, codecManager.getCatalog());

  43.        Map<String, ThriftMethodProcessor> processorMap = newHashMap();

  44.        for (ThriftMethodMetadata methodMetadata : thriftServiceMetadata.getMethods().values()) {

  45.            String methodName = methodMetadata.getName();

  46.            ThriftMethodProcessor methodProcessor = new ThriftMethodProcessor(service, thriftServiceMetadata.getName(), methodMetadata, codecManager);

  47.            if (processorMap.containsKey(methodName)) {

  48.                throw new IllegalArgumentException("Multiple @ThriftMethod-annotated methods named '" + methodName + "' found in the given services");

  49.            }

  50.            processorMap.put(methodName, methodProcessor);

  51.        }

  52.        Map<String, ThriftMethodProcessor> thriftMethodProcessorMap = ImmutableMap.copyOf(processorMap);

  53.        return thriftMethodProcessorMap;

  54.    }

  55.    public static byte[] clientSend(ThriftMethodHandler methodHandler, Object... args) {

  56.        ByteArrayOutputStream out = new ByteArrayOutputStream(1024);

  57.        TiostreamTransport transport = new TIOStreamTransport(out);

  58.        TProtocol outProtocol = new TBinaryProtocol.Factory().getProtocol(transport);

  59.        try {

  60.            methodHandler.send(outProtocol, sequenceId.getAndIncrement(), args);

  61.        } catch (Exception e) {

  62.            e.printStackTrace();

  63.        }

  64.        return out.toByteArray();

  65.    }

  66.    public static byte[] serverProcess(byte[] data) {

  67.        TProtocol in = new TBinaryProtocol.Factory().getProtocol(new TIOStreamTransport(new ByteArrayInputStream(data)));

  68.        TMessage message = null;

  69.        try {

  70.            message = in.readMessageBegin();

  71.        } catch (TException e) {

  72.            e.printStackTrace();

  73.        }

  74.        int sequenceId = message.seqid;

  75.        String methodName = message.name;

  76.        ThriftMethodProcessor methodProcessor = thriftMethodProcessorMap.get(methodName);

  77.        ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(1024);

  78.        TIOStreamTransport transport = new TIOStreamTransport(byteArrayOutputStream);

  79.        TProtocol out = new TBinaryProtocol.Factory().getProtocol(transport);

  80.        try {

  81.            methodProcessor.process(in, out, sequenceId);

  82.        } catch (Throwable t) {

  83.            t.printStackTrace();

  84.        }

  85.        return byteArrayOutputStream.toByteArray();

  86.    }

  87.    public static Object clientReceive(byte[] data, ThriftMethodHandler methodHandler) {

  88.        TProtocol in = new TBinaryProtocol.Factory().getProtocol(new TIOStreamTransport(new ByteArrayInputStream(data)));

  89.        Object result = null;

  90.        try {

  91.            result = methodHandler.receive(in, sequenceId.get() - 1);

  92.        } catch (Exception e) {

  93.            e.printStackTrace();

  94.        }

  95.        return result;

  96.    }

  97. }

此外还有一点需要说明的是,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注解支持的主要内容,如果未能解决你的问题,请参考以下文章

Thrift 代码分析

Thrift安装介绍

Apache Thrift系列详解- 概述与入门

Thrift介绍以及Java中使用Thrift实现RPC示例

Thrift架构介绍

Apache Thrift 的使用