升级版的Client和Server
首先让我们来重新定义Client和Server:SGClient和SGServer。SGClient封装了上一节定义的RPCClient的操作,提供服务治理的相关特性;SGServer则由上一节定义的RPCServer升级而来,支持服务治理的相关特性。这里的SG(service governance)表示服务治理。
这里直接贴上相关的定义:
type SGClient interface {
Go(ctx context.Context, ServiceMethod string, arg interface{}, reply interface{}, done chan *Call) (*Call, error)
Call(ctx context.Context, ServiceMethod string, arg interface{}, reply interface{}) error
}
type sgClient struct {
shutdown bool
option SGOption
clients sync.Map //map[string]RPCClient
serversMu sync.RWMutex
servers []registry.Provider
}
type RPCServer interface {
Register(rcvr interface{}, metaData map[string]string) error
Serve(network string, addr string) error
Services() []ServiceInfo
Close() error
}
type SGServer struct { //原来的RPCServer
codec codec.Codec
serviceMap sync.Map
tr transport.ServerTransport
mutex sync.Mutex
shutdown bool
Option Option
}
拦截器
在之前的文章提到过,我们需要提供过滤器一样的使用方式,来达到对扩展开放对修改关闭的目标。我们这里采用高阶函数的方式来定义方切面和法拦截器,首先定义几个切面:
//客户端切面
type CallFunc func(ctx context.Context, ServiceMethod string, arg interface{}, reply interface{}) error
type GoFunc func(ctx context.Context, ServiceMethod string, arg interface{}, reply interface{}, done chan *Call) *Call
//服务端切面
type ServeFunc func(network string, addr string) error
type ServeTransportFunc func(tr transport.Transport)
type HandleRequestFunc func(ctx context.Context, request *protocol.Message, response *protocol.Message, tr transport.Transport)
以上几个是RPC调用在客户端和服务端会经过的几个函数,我们将其定义为切面,然后再定义对应的拦截器:
//客户端拦截器
packege client
type Wrapper interface {
WrapCall(option *SGOption, callFunc CallFunc) CallFunc
WrapGo(option *SGOption, goFunc GoFunc) GoFunc
}
//f服务端拦截器
package server
type Wrapper interface {
WrapServe(s *SGServer, serveFunc ServeFunc) ServeFunc
WrapServeTransport(s *SGServer, transportFunc ServeTransportFunc) ServeTransportFunc
WrapHandleRequest(s *SGServer, requestFunc HandleRequestFunc) HandleRequestFunc
}
这样一来,用户可以通过实现Wapper接口来对客户端或者服务端的行为进行增强,比如将请求参数和结果记录到日志里,动态的修改参数或者响应等等。我们的框架自身 的相关功能也可以通过Wrapper实现。目前客户端实现了用于封装元数据的MetaDataWrapper和记录请求和响应的LogWrapper;服务端目前在DefaultWrapper实现了用于服务注册、监听退出信号以及请求计数的逻辑。
因为go并不提供抽象类的方式,所以对于某些实现类可能并不需要拦截所有切面(比如只拦截Call不想拦截Go),这种情况直接返回参数里的函数对象就可以了。