ProtoBuf 中的反射机制

我们先看一下JAVA反射的概念:
主要是指程序可以访问,检测和修改它本身状态或行为的一种能力,并能根据自身行为的状态和结果,调整或修改应用所描述行为的状态和相关的语义。
反射是Java中一种强大的工具,能够使我们很方便的创建灵活的代码,这些代码可以再运行时装配,无需在组件之间进行源代码链接。但是反射使用不当会成本很高!

说的很学术,看的也有点晕。 说白了就是,在运行时根据类的名字(字符串),创建类实例的能力。
当然还包含类的一些内部成员的信息,这样创建出来的实例就可以动态的调用类的方法以及成员。

JAVA在语言层面,提供了对Reflection的支持,当然还包括一些解释型语言也提供了反射支持,因为动态解释行语言支持起来是相对容易的。

C++ 在语言本身并没有支持反射机制,但是protobuf通过维护一些内部数据结构,提供了对proto文件生成的file, message, filed数据结构提供了反射的支持。
这对于远程调用,的类型识别作用非常大。试想一下,你只需要把message类型的字符串,和序列化的二禁止数据,传输给远端,远端服务器就可以根据message类型
构建类型对象,进而反序列化,还原本端的对象实例。应用程序,在也不用维护类型ID到对象实例的对应关系,这是非常方便的。

那么protobuf是怎么实现这种反射机制呢。下面我会从源码的角度分析一下。这里我们会从结果倒推回去的逆向逻辑。

1, 所有的生成的集成于message类型的子类,都实现了prototype 模式(支持从一个对象的实例,构造出另一个队像)。
2,  message的子类都有它本身的静态对象, 这样如果找到这个类静态对象,则可以使用这个对象new 一个新的对象实例。
class Person : public ::google::protobuf::Message /* @@protoc_insertion_point(class_definition:tutorial.Person) */ {
 public:
  Person();
  virtual ~Person();

  Person(const Person& from);

  inline Person& operator=(const Person& from) {
    CopyFrom(from);
    return *this;
  }
  static const ::google::protobuf::Descriptor* descriptor();
  static const Person& default_instance();              //一个今天的Person对象, 他的作用就是调用NEW生成新的对象。

  void Swap(Person* other);

  inline Person* New() const { return New(NULL); }      //New 会生成一个新的对象的指针。
  Person* New(::google::protobuf::Arena* arena) const;
  const ::google::protobuf::Descriptor* Person_descriptor_ = NULL;  //Person 的 Descriptor
 
3,message类的Descriptor会跟 default_instance,建立一个映射,这样就能通过Descriptor找到default_instance
   这个映射关系的建立,引入了另外一个中间的类。
   void protobuf_RegisterTypes(const ::std::string&) {
      protobuf_AssignDescriptorsOnce();
      ::google::protobuf::MessageFactory::InternalRegisterGeneratedMessage(
      Person_descriptor_, &Person::default_instance());  //这里MessageFactory会注册Descriptor到default_instance的映射关系。

4, 那接下来要做什么呢,当然是怎样找到一个message的Descriptor.
   class LIBPROTOBUF_EXPORT DescriptorPool {
   public:
   // Create a normal, empty DescriptorPool.
   DescriptorPool();
      const Descriptor* FindMessageTypeByName(const string& name) const;   //DescriptorPool是一个全局对象, 他提供了根据字符串找到 Descriptor的机制。
   const FieldDescriptor* FindFieldByName(const string& name) const;
   const FieldDescriptor* FindExtensionByName(const string& name) const;
   const OneofDescriptor* FindOneofByName(const string& name) const;
   const EnumDescriptor* FindEnumTypeByName(const string& name) const;
   const EnumValueDescriptor* FindEnumValueByName(const string& name) const;
   const ServiceDescriptor* FindServiceByName(const string& name) const;
   const MethodDescriptor* FindMethodByName(const string& name) const;

//第一种方式:  
Classc1 = Class.forName("Employee");  
//第二种方式:  
//java中每个类型都有class 属性.  
Classc2 = Employee.class;  
   
//第三种方式:  
//java语言中任何一个java对象都有getClass 方法  
Employee  e = new Employee();  
Classc3 = e.getClass(); //c3是运行时类 (e的运行时类是Employee)

猜你喜欢

转载自blog.csdn.net/abccheng/article/details/62892598