Dubbo/Dubbox、Google gRPC、RPCX、Spring Boot/Spring Cloud 如此多的RPC框架 咱们当然要理解下他们的原理呀

咱们以 LightRPC github.com/dollarkillerx/light 为例 写一个属于本人的RPC

最初的成绩是怎么的

https://github.com/dollarkill...

payload:

// 申请体strcut Request {    Msg string}// 返回体struct Response {    Msg string}

server:

// 定义根底服务struct HelloWorldServer {}func (h *HelloWorldServer) HelloWorld(ctx *light.Context, request *Request, response *Response) error {    response.Msg = fmt.Sprintf("request: %s  ",request.Msg)    return nil}// 启动服务func main() {     ser := server.NewServer()     err := ser.RegisterName(&HelloWorldServer{}, "HelloWorldServer")  // 注册 服务    if err != nil {        log.Fatalln(err)     }         // 监听服务    if err := ser.Run(server.UseTCP("0.0.0.0:8074")); err != nil {        log.Fatalln(err) }     }

client:

    client := client.NewClient(discovery.NewSimplePeerToPeer("127.0.0.1:8074", transport.TCP))    connect, err := client.NewConnect("HelloWorldServer") // 对特定服务 建设连贯    if err != nil {        log.Fatalln(err)        return    }    req := Request{        Msg: "hello",    }    resp := Response{}    err = connect.Call(light.DefaultCtx(), "HelloWorld", &req, &resp) // 调用某个服务    if err != nil {        log.Fatalln(err)    }                fmt.Println(resp)

这就是咱们要实现的根底服务, 咱们能够在这个服务之上增加 服务发现与注册 熔断器 监控 等等...

1. 实现服务外部注册

先看看server端的根底需要:

  • [ ] 1. 一个server端能够注册多个服务
  • [ ] 2. middleware

咱们先定义一个服务管理器 以治理多个服务

type MiddlewareFunc func(ctx *light.Context, request interface{}, response interface{}) error// 定义服务管理器type Server struct {    serviceMap map[string]*service  // 服务应用map的形式进行注册    options    *Options             // 相干的配置    beforeMiddleware     []MiddlewareFunc       // 全局前置middleware    afterMiddleware      []MiddlewareFunc       // 全局后置middleware    beforeMiddlewarePath map[string][]MiddlewareFunc   // 特定路由 前置middleware    afterMiddlewarePath  map[string][]MiddlewareFunc   // 特定路由 后置middleware}// 定义单个服务type service struct {    name       string                 // server name   服务名称    refVal     reflect.Value          // server reflect value    refType    reflect.Type           // server reflect type    methodType map[string]*methodType // server method  服务具体的办法}

咱们刚刚定义了这个服务 当初开始 实现服务的初始化代码

func NewServer() *Server {    return &Server{        serviceMap: map[string]*service{},        options:    defaultOptions(),        beforeMiddleware:     []MiddlewareFunc{},        afterMiddleware:      []MiddlewareFunc{},        beforeMiddlewarePath: map[string][]MiddlewareFunc{},        afterMiddlewarePath:  map[string][]MiddlewareFunc{},    }}

当初来编写服务注册 这是本章的重点 !!!

咱们会定义两个 服务注册的形式

  1. 通过 Register() 间接注册服务, 服务名称 设置为以后构造体的名称
  2. 通过 RegisterName() 进行服务注册, 能够传入服务名称 进行设置
func (s *Server) Register(server interface{}) error {    return s.register(server, "", false)}func (s *Server) RegisterName(server interface{}, serverName string) error {    return s.register(server, serverName, true)}// 具体服务注册办法func (s *Server) register(server interface{}, serverName string, useName bool) error {    ser, err := newService(server, serverName, useName)  // 生成一个服务    if err != nil {        return err    }    s.serviceMap[ser.name] = ser  // 放到serviceMap中去    return nil}

结构具体服务

func newService(server interface{}, serverName string, useName bool) (*service, error) {    ser := &service{        refVal:  reflect.ValueOf(server),        refType: reflect.TypeOf(server),    }        // 获取服务名称    sName := reflect.Indirect(ser.refVal).Type().Name()    if !utils.IsPublic(sName) {  // IsPublic 判断 是否是Public        return nil, pkg.ErrNonPublic    }    if useName {        if serverName == "" {            return nil, errors.New("Server Name is null")        }        sName = serverName    }    ser.name = sName                // constructionMethods 获取以后构造体的 合规办法 进行注册    methods, err := constructionMethods(ser.refType)    if err != nil {        return nil, err    }    ser.methodType = methods    for _, v := range methods {        log.Println("Registry Service: ", ser.name, "   method: ", v.method.Name)    }    return ser, nil}// constructionMethods Get specific methodfunc constructionMethods(typ reflect.Type) (map[string]*methodType, error) {    methods := make(map[string]*methodType)    for idx := 0; idx < typ.NumMethod(); idx++ {  // 咱们对以后struct的办法进行遍历 找到合乎的办法进行注册        method := typ.Method(idx)        mType := method.Type        mName := method.Name        if !utils.IsPublic(mName) {            return nil, pkg.ErrNonPublic        }        // 默认是4个        if mType.NumIn() != 4 { // func(*server.MethodTest, *light.Context, *server.MethodTestReq, *server.MethodTestResp) error            continue        }        // 测验它第一个参数是否是ctx        ctxType := mType.In(1)        if !(ctxType.Elem() == typeOfContext) {            continue        }        // request 参数查看        requestType := mType.In(2)        if requestType.Kind() != reflect.Ptr {            continue        }                                // 穷举的查看是否均所有参数均为 public        if !utils.IsPublicOrBuiltinType(requestType) {            continue        }        // response 参数查看        responseType := mType.In(3)        if responseType.Kind() != reflect.Ptr {            continue        }        if !utils.IsPublicOrBuiltinType(responseType) {            continue        }        // 校验返回参数        if mType.NumOut() != 1 {            continue        }        returnType := mType.Out(0)        if returnType != typeOfError {            continue        }        methods[mName] = &methodType{            method:       method,            RequestType:  requestType,            ResponseType: responseType,        }    }    if len(methods) == 0 {        return nil, pkg.ErrNoAvailable    }    return methods, nil}

下面咱们就实现了根底的服务注册了