主题
Day 4 技术设计文档 — 服务注册与反射调用
核心数据结构
go
type methodType struct {
method reflect.Method // 方法的反射信息
ArgType reflect.Type // 入参类型
ReplyType reflect.Type // 出参类型(指针)
numCalls uint64 // 调用次数(原子操作)
}
type service struct {
name string // 服务名(类型名)
typ reflect.Type // 接收者类型
rcvr reflect.Value // 接收者实例
method map[string]*methodType // 方法名 -> 方法信息
}方法发现流程
方法签名校验规则
go
// 合法方法必须满足以下条件:
mType.NumIn() == 3 // receiver, args, *reply
mType.NumOut() == 1 // error
mType.Out(0) == reflect.TypeOf((*error)(nil)).Elem()
isExportedOrBuiltinType(argType)
isExportedOrBuiltinType(replyType)newArgv / newReplyv 的指针处理
go
func (m *methodType) newArgv() reflect.Value {
if m.ArgType.Kind() == reflect.Ptr {
// 参数是指针类型:reflect.New 返回 *T
return reflect.New(m.ArgType.Elem())
}
// 参数是值类型:reflect.New 返回 *T,取 Elem 得到 T
return reflect.New(m.ArgType).Elem()
}
func (m *methodType) newReplyv() reflect.Value {
// Reply 始终是指针类型
replyv := reflect.New(m.ReplyType.Elem())
// 特殊处理 map 和 slice:需要初始化
switch m.ReplyType.Elem().Kind() {
case reflect.Map:
replyv.Elem().Set(reflect.MakeMap(m.ReplyType.Elem()))
case reflect.Slice:
replyv.Elem().Set(reflect.MakeSlice(m.ReplyType.Elem(), 0, 0))
}
return replyv
}反射调用
go
func (s *service) call(m *methodType, argv, replyv reflect.Value) error {
atomic.AddUint64(&m.numCalls, 1)
f := m.method.Func
// Func.Call 的第一个参数是 receiver
returnValues := f.Call([]reflect.Value{s.rcvr, argv, replyv})
if errInter := returnValues[0].Interface(); errInter != nil {
return errInter.(error)
}
return nil
}使用 atomic.AddUint64 进行无锁计数,在高并发场景下性能优于 mutex。