今天在使用golang的protoful作为通信消息协议的时候,发现我们必须手动写死消息名称来对应处理消息的func,极为不便,不符合策略模式的设计模式,经过一天的查找最终找到以下解决方法
获取proto Message的全类名
// GetFullNameByMessage 获取pb协议的全类名
func GetFullNameByMessage(msg proto.Message) string {
reflect := proto.MessageReflect(msg)
descriptor := reflect.Descriptor()
name := descriptor.FullName()
return string(name)
}
根据proto全类名获取Message实例
func GetMessageByFullName(fullName string, data []byte) proto.Message {
msgName := protoreflect.FullName(fullName)
msgType, err := protoregistry.GlobalTypes.FindMessageByName(msgName)
if err != nil {
logger.Errorf("FindMessageByName err: %v", err)
return nil
}
msg := proto.MessageV1(msgType.New())
err = proto.Unmarshal(data, msg)
if err != nil {
logger.Errorf("proto Unmarshal err: %v", err)
return nil
}
return msg
}
该方法只在golang proto v1版本才能使用,也就是
github.com/golang/protobuf
的包名
如果是V2版本请使用以下方法,也就是google.golang.org/protobuf/proto
包
// GetMessageV2ByFullName 根据pb全类名获取消息实例
func GetMessageV2ByFullName(fullName string, data []byte) proto.Message {
msgName := protoreflect.FullName(fullName)
msgType, err := protoregistry.GlobalTypes.FindMessageByName(msgName)
if err != nil {
logger.Errorf("FindMessageByName err: %v", err)
return nil
}
message := msgType.New().Interface()
err := proto.Unmarshal(data, message)
if err != nil {
return nil
}
return message
}