Skip to content

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。