在brpc(buttonrpc)开源框架的基础上,实现了自动生成rpc接口,用户编写好源码后,一键生成rpc stub,即可直接使用rpc服务。目前已大体实现。
项目地址
https://github.com/CharmsGraker/brpc
功能
brpc中原本是通过client.call<void>("classMem::func1", param1);
这样实现的。
那么可以对其再包裹一层。为对象生成一个代理类ClassMem_proxy
,并且这些proxy类全部自动实现。
...
class buttonrpc;
class ClassMem_proxy {
ClassMem_proxy(buttonrpc * c){
client = c;
}
void func1(double param1) {
client->call<void>("func1", param1);
}
private:
buttonrpc * client;
};
这样,客户就能如下几乎无感调用了。
...
int main() {
buttonrpc client;
client.as_client(5555);
ClassMem_proxy classMem(client);
classMem->func1(2.0); // invoke RPC
}
实现
相应的,这就需要在rpc server启动前自动bind
好这些rpc方法。然后生成好这些proxy类。这些代码全部自动生成,不需要用户操心。也不需要用户再源代码中引入任何文件。只需用户期望注入时,build一下。(目前还未编写批量build)
而且一旦build好后,用户只要不修改RPC方法的返回或参数类型,可以自由更改源代码逻辑。
自动化代码构建的脚本入口位于stub_generator/main.cpp
服务端代码生成在stub_generator/Startup.h
RPC标记
客户可以只加入会使用到的函数到RPC服务器。
可以采用标记对其控制,支持类的部分成员函数注入,或某些函数(不)注入到RPC服务器。
只需要在方法上按如下方式标记上@RPC_INJECT
或@RPC_NOT_INJECT
,默认行为是注入。
// @RPC_INJECT
// 这个方法会被注入
void func();
// @RPC_NOT_INJECT
// 这个方法不会被注入
double func2(int a);
如果头文件里包含了多个类、多个方法,也可以不全部注入这些类、方法。
这部分的实现位于classparser.h和headerparser.h,完成对某个类或头文件中方法和成员的签名解析。
静态代理
由于C++实现动态代理有困难,最终还是采用静态代理的方式。
服务器会在启动前,把已注入RPC方法的类全部写入到runtime_class.h
头文件中。runtime_class.h
只包含了基础的模板方法。
runtime_class.cpp
包含了对于不同类的特化函数版本,如下:
// runtime_class.cpp
template<>
std::string getClassName(classMem *) {
return "classMem";
}
这个函数是方便server可以从对象池中取得对象。此时运行时的每个类都会有名字了。(对于基本类型,可以手动对模板展开一下加入到runtime_class.cpp)
对象池(实现中)
利用上面的getClassName,我们可以在执行RPC方法的时候自定义RPC对象的创建策略。
目前仅仅使用默认构造器。未来的改进是允许直接从用户传输的数据中构建对象。并且可以服用对象并缓存到对象池中。