rpcx服务框架浅析11-调用拦截链

RPCX分布式服务框架主要致力于提供高性能和透明化的RPC远程服务调用。

      拦截器 :是在面向切面编程中应用的,就是在你的service或者一个方法前调用一个方法,或者在方法后调用一个方法。比如java的动态代理就是拦截器的简单实现,在你调用方法前打印出字符串(或者做其它业务逻辑的操作),也可以在你调用方法后打印出字符串。RPCX框架中并没有调用拦截的处理(扫源代码好像没看到)

      拦截链:多个拦截器构成一个链,完成一组拦截,可能还有执行的先后顺序(任务职责链)。

拦截链简单实现

输入参数:

type CmdIn struct {
	Param string
}

func (this *CmdIn) String() string {
	return fmt.Sprintf("[CmdIn Param is %s]",this.Param)
}

输出参数:

type CmdOut struct {
	Result int
	Info string
}

func (this *CmdOut) String() string {
	return fmt.Sprintf("Result[%d] Info[%s]",this.Result,this.Info)
}

处理Handler:

type Hello struct {
	Param string
}

func (this *Hello) Test1(ctx context.Context, in *CmdIn, out *CmdOut) error {
	fmt.Println("接收到服务消费方输入:",in.Param)
	out.Result=12345678
	out.Info="我已经吃饭了!"
	return nil
}

封装Invoker:

package defines

import (
	"fmt"
	"context"
	"reflect"
	"unicode"
	"unicode/utf8"
	"container/list"
)

var typeOfError = reflect.TypeOf((*error)(nil)).Elem()
var typeOfContext = reflect.TypeOf((*context.Context)(nil)).Elem()

type MethodType struct {
	method			reflect.Method
	ArgType    		reflect.Type
	ReplyType  		reflect.Type
}

type Reflect struct {
	Name     string
	Rcvr     reflect.Value
	Typ      reflect.Type
	Method   map[string]*MethodType
	filter   *list.List
}

func (this *Reflect) Setup(rcvr interface{}, name string,filter *list.List) {
	this.Typ = reflect.TypeOf(rcvr)
	this.Rcvr = reflect.ValueOf(rcvr)
	this.Name = reflect.Indirect(this.Rcvr).Type().Name()
	this.Method = suitableMethods(this.Typ, true)
	this.filter=filter
}

func (this *Reflect) Call(ctx context.Context,service string,method string,in *CmdIn,out *CmdOut) error {
	for e := this.filter.Front(); e != nil; e = e.Next() {
		f:=e.Value.(Filter)
		err:=f.Invoke(ctx,service,method,in,out)
		if err!=nil{
			return err
		}
	}

	mtype := this.Method[method]
	returnValues := mtype.method.Func.Call([]reflect.Value{this.Rcvr, reflect.ValueOf(ctx), reflect.ValueOf(in), reflect.ValueOf(out)})
	errInter := returnValues[0].Interface()
	if errInter != nil {
		return errInter.(error)
	}else{
		return nil
	}
}

func suitableMethods(typ reflect.Type, reportErr bool) map[string]*MethodType {
	methods := make(map[string]*MethodType)
	for m := 0; m < typ.NumMethod(); m++ {
		method := typ.Method(m)
		mtype := method.Type
		mname := method.Name
		if method.PkgPath != "" {
			continue
		}
		if mtype.NumIn() != 4 {
			if reportErr {
				fmt.Println("method", mname, "has wrong number of ins:", mtype.NumIn())
			}
			continue
		}
		ctxType := mtype.In(1)
		if !ctxType.Implements(typeOfContext) {
			if reportErr {
				fmt.Println("method", mname, " must use context.Context as the first parameter")
			}
			continue
		}

		argType := mtype.In(2)
		if !isExportedOrBuiltinType(argType) {
			if reportErr {
				fmt.Println(mname, "parameter type not exported:", argType)
			}
			continue
		}
		// Third arg must be a pointer.
		replyType := mtype.In(3)
		if replyType.Kind() != reflect.Ptr {
			if reportErr {
				fmt.Println("method", mname, "reply type not a pointer:", replyType)
			}
			continue
		}
		// Reply type must be exported.
		if !isExportedOrBuiltinType(replyType) {
			if reportErr {
				fmt.Println("method", mname, "reply type not exported:", replyType)
			}
			continue
		}
		// Method needs one out.
		if mtype.NumOut() != 1 {
			if reportErr {
				fmt.Println("method", mname, "has wrong number of outs:", mtype.NumOut())
			}
			continue
		}
		// The return type of the method must be error.
		if returnType := mtype.Out(0); returnType != typeOfError {
			if reportErr {
				fmt.Println("method", mname, "returns", returnType.String(), "not error")
			}
			continue
		}
		methods[mname] = &MethodType{method: method, ArgType: argType, ReplyType: replyType}
	}
	return methods
}

func isExportedOrBuiltinType(t reflect.Type) bool {
	for t.Kind() == reflect.Ptr {
		t = t.Elem()
	}
	return isExported(t.Name()) || t.PkgPath() == ""
}

func isExported(name string) bool {
	rune, _ := utf8.DecodeRuneInString(name)
	return unicode.IsUpper(rune)
}

拦截器定义:

type Filter interface {
	Invoke(ctx context.Context,service string,method string,in interface{},out interface{}) error
}
//限制用拦截器
type LimitFilter struct {
}

func (this *LimitFilter) Invoke(ctx context.Context,service string,method string,in interface{},out interface{}) error {
	fmt.Println("拦截链 LimitFilter process")
	return nil
}

//调用统计拦截器
type StatisticsFilter struct {
}

func (this *StatisticsFilter) Invoke(ctx context.Context,service string,method string,in interface{},out interface{}) error {
	fmt.Println("拦截链 StatisticsFilter process")
	return nil
}

调用示例:

func TestReflect_Setup(t *testing.T) {
	filters:=list.New()                    //拦截链
	filters.PushBack(&LimitFilter{})       //拦截组件1
	filters.PushBack(&StatisticsFilter{})  //拦截组件2

	hello:=&Hello{}
	reflect:=&Reflect{}
	reflect.Setup(hello,"Hello",filters)

	fmt.Println("发起消费方调用")
	in:=&CmdIn{
		Param:"吃饭了吗?",
	}
	out:=&CmdOut{}
	err:=reflect.Call(context.Background(),"Hello","Test1",in,out)
	if err!=nil {
		fmt.Println(err)
	}else{
		fmt.Println("接收到服务提供方返回:",out)
	}
}

程序执行结果:

1.发起消费方调用
2.拦截链 LimitFilter process
3.拦截链 StatisticsFilter process
4.接收到服务消费方输入: 吃饭了吗?
5.接收到服务提供方返回: Result[12345678] Info[我已经吃饭了!]

系列文章

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值