Thrift源码修改,改造RPC,支持多Processor[java版]

本文介绍了如何通过修改Thrift源码,将原本只支持单个接口的RPC模式改造为支持多个Processor,从而允许共享端口并方便服务管理。改造涉及服务端和客户端的多个类,包括TSimpleServer、TThreadPoolServer、AbstractNonblockingServer、TBaseProcessor、TProcessorFactory等。改造主要思路是将final类型的processor改为从初始化到容器中,并在客户端传输TMessage时加入类信息。通过类扫描器和服务注解加载不同Processor。服务端启动时,调用TProcessorFactory的初始化方法,实现了多接口模式。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

说明:基于0.8.0版本

 

Thrift rpc只提供单个接口的模式,一个TServerSocket只能实例化一个Processor实际上,当接口的模式再实际应用的过程中也许会比较少,不知道为什facebook要这么做,每开放一个服务接口都得占用一个端口,对于服务的管理也会带来不便。采用共用端口的模式可以解决端口问题,但是单个进程好像还是可以加载一个Processor,不知道是不是没找对方法。

 

为了实现加载多Processor需求,开始对thrift源码做相关的修改。

 

【服务端相关改造】

需要修改的类:

TSimpleServer(阻塞,简单模式,一般不怎么用)

TThreadPoolServer.WorkerProcess(阻塞、线程池模式)

AbstractNonblockingServer(非阻塞模式)

TBaseProcessor

TProcessorFactory

 

【客户端相关改造】

需要修改的类:

TServiceClient(阻塞)

TCompactProtocol(非阻塞)

 

【新增的类】

ClassScanner(类扫描器,加载processor

Service(服务注解)

 

代码分析:

先看看服务端的启动的例子

TServerSocket serverTransport = new TServerSocket(8811);

ServiceDemo.Processor processor = new ServiceDemo.Processor(newServiceDemoImpl());

Factory protFactory = new TBinaryProtocol.Factory(true,true);

Args rpcArgs = new Args(serverTransport);

rpcArgs.processor(processor);

rpcArgs.protocolFactory(protFactory);

TServer server = new TThreadPoolServer(rpcArgs);

server.serve();

 

所有生成代码的Processor均继承TBaseProcessor,因此首先分析TBaseProcessor

具体可看TBaseProcessor的属性private final I iface,这里的iface实例声明是final,同时生成的客户端代吗也可以看出。

privatestatic <Iextends Iface>Map<String, org.apache.thrift.ProcessFunction<I, ?extends org.apache.thrift.TBase>> getProcessMap(Map<String, org.apache.thrift.ProcessFunction<I, ? extends org.apache.thrift.TBase>>processMap) {

      processMap.put("test",new test());

      return processMap;

}

这里的processMapkey为方法名,在发送的时候,该key将会组装到TMessagename中,并没有把类的相关信息带过去。这也是为啥thrift不支持方法重载的原因,应该是考虑到其他有些语言不支持重载的原因,比如C

 

再看TProcessorFactory

public class TProcessorFactory {

 private final TProcessor processor_;

 public TProcessorFactory(TProcessor processor) {

   processor_ = processor;

  }

 public TProcessor getProcessor(TTransport trans) {

   return processor_;

  }

}

这里的TProcessor也是final类型,服务器启动过程中,会调用该构造函数,实例化processor_属性,执行rpcArgs.processor(processor)的时候,会初始化ProcessorFactory,具体可以看AbstractServerArgs的方法

public Tprocessor(TProcessor processor) {

     this.processorFactory = new TProcessorFactory(processor);

     return (T) this;

}

 

看到这里,大概的思路就清楚了,主要有两点:

1、 把final类型的processor改为从初始化到容器中;

2、 客户端传输TMessage加入类的信息;

 

 

先看客户调用的修改,分阻塞和非阻塞两种模式

 

对于阻塞模式,只修改一个类TServiceClient

由于生成工具无法修改,因此无法从修改生成代码结构处理,只能从调用的库上做文章,实际上,所有Client的接口具有两步处理,发送-接收,均调用TServiceClient中的方法sendBase /receiveBase,只需要在sendBase中加入类信息到TMessage中即可,如下:

protected voidsendBase(String methodName, TBase args) throws TException {

               // 处理调用接口

               String className = "";

               StackTraceElement stack[] = (new Throwable()).getStackTrace();

               if (stack.length > 1) {

                           StackTraceElementste = stack[1];

                           className =ste.getFileName();

                           className =className.split("\\.")[0];

               }

               oprot_.writeMessageBegin(new TMessage(className+ "_" + methodName, TMessageType.CALL, ++seqid_));

               args.write(oprot_);

               oprot_.writeMessageEnd();

               oprot_.getTransport().flush();

  }

红色部分为获取类名,writeMessageBegin的时候加入即可,默认格式:类名_方法名;这里去的类名并非内部类Processor,而是生成的服务接口文件名,比如ServiceDemo,其内部结构如下:

 

同样,在服务端初始化Processor容器的时候也取改类文件名。

 

对于非阻塞模式,需要修改TCompactProtocol类,

同样的原理,修改

publicvoidwriteMessageBegin(TMessagemessage)throws TException {

     //处理调用接口

     String className = "";

     StackTraceElement stack[] = (new Throwable()).getStackTrace();

     if (stack.length > 1) {

         StackTraceElement ste = stack[1];

         className = ste.getFileName();

         className = className.split("\\.")[0];

     }

    writeByteDirect(PROTOCOL_ID);

    writeByteDirect((VERSION &VERSION_MASK) |((message.type <<TYPE_SHIFT_AMOUNT) &TYPE_MASK));

    writeVarint32(message.seqid);

    writeString(className + "_" + message.name);  //加入类名,格式:类名_方法名

}

至此,第一步完成。

 

下面修改服务端处理

 

1、  修改TProcessorFactory

保持原来的内容,只新增容器,新增Processor存取方法,加入processor容器加载的处理,需要用到类扫描器(ClassScanner)和对应的服务注解类(org.apache.thrift.Service),后面会介绍初始化的处理方法,具体如下:

publicclass TProcessorFactory {

     privatestatic Loggerlogger = Logger.getLogger(TProcessorFactory.class);

     privatefinal TProcessorprocessor_;

     //新增processor容器

     privatestatic MapprocessorMap =new HashMap();

     //新增function容器

     privatestatic MapfunctionMap =new HashMap();

     public TProcessorFactory(TProcessor processor) {

         processor_ = processor;

     }

     public TProcessor getProcessor(TTransport trans) {

         returnprocessor_;

     }

     /**

      * @Title: addProcessor

      * @Description:新增方法-加入processor到容器

      * @param@param key

      * @param@param processor

      * @return void

      */

     publicstaticvoid addProcessor(String key, Object processor) {

         if (processorMap.containsKey(key)) {

              return;

         }

         processorMap.put(key, processor);

         logger.info("加载Processor" +processor.getClass

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值