Gone框架介绍32 - 函数参数的依赖注入

gone是可以高效开发Web服务的Golang依赖注入框架
github地址:https://github.com/gone-io/gone
文档地址:https://goner.fun/zh/

函数参数的依赖注入

函数参数的依赖注入,是v1.x版本正式发布的新功能,允许使用Goners仓库中的Goners来自动生成函数的参数对应的[]reflect.Value数组。这个功能由Cemetery接口的InjectFuncParameters方法提供。

业务编写上,一般情况,不推荐使用该功能;如果尝试扩展Gone框架的功能,可以使用该功能。

InjectFuncParameters 方法说明

  • 方法定义
InjectFuncParameters(
    fn any,
    injectBefore func(pt reflect.Type, i int) any,
    injectAfter func(pt reflect.Type, i int),
) (args []reflect.Value, err error)
  • 入参说明:
    • fn,需要被注入的函数;函数允许拥有多个入参,入数可以是Gone框架中注册的接口或者结构体指针,也可以为被gone标记了属性的结构体,一般使用匿名结构体;
    • injectBefore,hook函数,在对第i个参数构造前调用,如果injectBefore(x, i)返回值非nil,InjectFuncParameters将不再构造fn函数的第i个参数,而是将该值的reflect.Value直接作为args数组的第i个值;
    • injectAfter,hook函数,在对第i个参数成功构造后调用;
  • 出参说明
    • args,fn参数的reflect.Value数组
    • err,函数构造返回的错误
  • 功能说明:
    根据fn函数的定义和Gone框架中注册的Goners,自动构造fn的参数数组args。然后可以使用func (v Value) Call(in []Value) []Value对函数进行调用。

Gone 源代码中使用例子

WrapNormalFnToProcess

func WrapNormalFnToProcess(fn any) Process {

    // Process函数只有一个 Cemetery 参数
	return func(cemetery Cemetery) error {

        // 根据函数的定义,使用 cemetery.InjectFuncParameters 构造 函数的参数数组
		args, err := cemetery.InjectFuncParameters(fn, nil, nil)
		if err != nil {
			return err
		}

        //使用 reflect.ValueOf(fn).Call(args) 对函数进行调用
		results := reflect.ValueOf(fn).Call(args)
		for _, result := range results {
			if err, ok := result.Interface().(error); ok {
				return err
			}
		}
		return nil
	}
}

上面代码是截止于Gone中help.go,作用是将一个函数转换为Process。在看prepare.go中的代码:

//...
func (p *Preparer) BeforeStart(fn any) *Preparer {
	p.heaven.BeforeStart(WrapNormalFnToProcess(fn))
	return p
}

func (p *Preparer) AfterStart(fn any) *Preparer {
	p.heaven.AfterStart(WrapNormalFnToProcess(fn))
	return p
}

func (p *Preparer) BeforeStop(fn any) *Preparer {
	p.heaven.BeforeStop(WrapNormalFnToProcess(fn))
	return p
}

func (p *Preparer) AfterStop(fn any) *Preparer {
	p.heaven.AfterStop(WrapNormalFnToProcess(fn))
	return p
}

func (p *Preparer) SetAfterStopSignalWaitSecond(sec int) {
	p.heaven.SetAfterStopSignalWaitSecond(sec)
}

func (p *Preparer) Run(fns ...any) {
	p.SetAfterStopSignalWaitSecond(0)
	for _, fn := range fns {
		p.AfterStart(fn)
	}
	p.heaven.
		Install().
		Start().
		Stop()
}
//...

可以看到,通过PreparerBeforeStartAfterStartBeforeStopAfterStop方法,可以将任意函数转换为Process,然后注册到Heaven中,原理上就是通过WrapNormalFnToProcess将任意函数转为了Process函数;Preparer.Run 方法之所以支持任意参数的函数,也是潜在的通过WrapNormalFnToProcess函数实现的。

buildProxyFn

buildProxyFn方法的代码截取于goner/gin/proxy.go,是实现HTTP请求参数注入的关键函数,作用是将一个任意参数的函数转换为gin.HandlerFunc,然后就可以注册到gin.Engine中。使用InjectFuncParameters的目的是收集依赖,在函数构造前对Goners进行注入,对HTTP请求参数的依赖延迟到函数执行阶段完成注入。

//...

func (p *proxy) buildProxyFn(x HandlerFunc, funcName string, last bool) gin.HandlerFunc {
	m := make(map[int]*bindStructFuncAndType)
	args, err := p.cemetery.InjectFuncParameters(
		x,

        //传入 hook injectBefore,完成 特殊参数的过滤
		func(pt reflect.Type, i int) any {
            //...
		},

        // 传入 hook injectAfter,收集 HTTP请求参数的依赖
		func(pt reflect.Type, i int) {
            //...
		},
	)

	if err != nil {
		p.Panicf("build Proxy func for \033[31m%s\033[0m error:\n\n%s", funcName, err)
	}

	fv := reflect.ValueOf(x)
	return func(context *gin.Context) {
		//...
        // 延迟注入 HTTP请求参数的依赖
        //...

		//call the func x
		values := fv.Call(parameters)

		//...
	}
}

//...
  • 5
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

dapeng-大鹏

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值