99行代码实现go IOC容器

Configuration(args...): 代码会自动调用结构中"方法名与返回值类型名称一致的方法,进行初始化beanMap"

Set(args...): 该注入方式支持使用结构体中tag,其标记为:inject,默认标记值为`inject:"auto"`或`inject:""`或不写tag,以上方式都以单例方式注入,
若填入标记的值为"结构.方法的类型",如:`inject:"ServiceB.Hello()"`或`inject:"ServiceB.Hello"`,则会调用ServiceB的Hello方法进行依赖注入,
若ServiceA结构中包含了ServiceB,则使用tag`inject:"ServiceA.Hello()"`或`inject:"ServiceA.Hello"`方式也可注入,
前提是ServiceA中的Hello方法返回值类型为目标类型,仅当结构体中字段为Struct指针类型时,才可注入成功

Get(bean): 该方法返回容器中的Bean,使用前须判断是否为空指针,依赖注入方式为懒注入方式,仅当调用Get方法时才进行一次性注入(单例),动态注入(多例)
*/
package main

import (
	"fmt"
	"reflect"
	"strings"
)

var beanMap map[reflect.Type]reflect.Value
var funcMap map[string]any

func init() {
	beanMap = make(map[reflect.Type]reflect.Value)
	funcMap = make(map[string]any)
}

func Set(beans ...any) {
	for i := range beans {
		_type := reflect.TypeOf(beans[i])
		if !(_type.Kind() == reflect.Ptr && _type.Elem().Kind() == reflect.Struct) {
			panic("it is not struct pointer")
		}
		if _, ok := beanMap[reflect.ValueOf(beans[i]).Type()]; !ok {
			beanMap[reflect.ValueOf(beans[i]).Type()] = reflect.ValueOf(beans[i])
			funcMap[reflect.TypeOf(beans[i]).Elem().Name()] = beans[i]
		}
	}
}

func Get[T any](bean T) T {
	if t := reflect.TypeOf(bean); !(t.Kind() == reflect.Ptr && t.Elem().Kind() == reflect.Struct) {
		return bean
	}

	if beanPtr, ok := beanMap[reflect.TypeOf(bean)]; ok {
		beanPtrType := reflect.TypeOf(beanPtr.Interface().(T)).Elem()
		beanPtrValue := reflect.ValueOf(beanPtr.Interface().(T)).Elem()
		for i := 0; i < beanPtrType.NumField(); i++ {
			tField, vField := beanPtrType.Field(i), beanPtrValue.Field(i)
			if tField.Type.Kind() == reflect.Ptr &&
				tField.Type.Elem().Kind() == reflect.Struct &&
				vField.IsNil() && vField.CanSet() {
				switch tag := tField.Tag.Get("inject"); {
				case tag == "auto" || tag == "": //单例模式
					if ptr := Get(vField.Interface()); ptr != nil {
						vField.Set(reflect.ValueOf(ptr))
					}
				default: //多例模式
					str := strings.Split(tag, ".")
					if len(str) != 2 {
						panic("inject tag: " + tag + " error")
					}
					StructName, FuncName := str[0], strings.ReplaceAll(str[1], "()", "")

					if mt, isOk := reflect.TypeOf(funcMap[StructName]).MethodByName(FuncName); isOk {
						if mt.Type.NumIn() == 1 && mt.Type.NumOut() == 1 && //入参1(接收者本身) 出参1(创建的结构体指针)
							mt.Type.Out(0).Kind() == reflect.Ptr &&
							mt.Type.Out(0).Elem().Kind() == reflect.Struct &&
							vField.Type().Elem().Name() == mt.Type.Out(0).Elem().Name() { // 类型一致
							instance := mt.Func.Call([]reflect.Value{reflect.ValueOf(funcMap[StructName])})[0]
							vField.Set(reflect.ValueOf(instance.Interface()))
							if _, okay := beanMap[reflect.TypeOf(instance.Interface())]; !okay {
								beanMap[reflect.TypeOf(instance.Interface())] = reflect.ValueOf(instance.Interface())
							}
						}
					} else {
						panic("inject tag: " + tag + " method not found")
					}
				}
			}
		}
		return beanPtr.Interface().(T)
	}
	return bean
}

func Configuration(configs ...interface{}) {
	for i := range configs {
		_type := reflect.TypeOf(configs[i])
		if !(_type.Kind() == reflect.Ptr && _type.Elem().Kind() == reflect.Struct) {
			panic("it is not struct pointer")
		}

		funcMap[reflect.TypeOf(configs[i]).Elem().Name()] = configs[i]
		for j := 0; j < _type.NumMethod(); j++ {
			mt := _type.Method(j).Type
			if mt.NumIn() == 1 && mt.NumOut() == 1 && //入参1(接收者本身) 出参1(创建的结构体指针)
				mt.Out(0).Elem().Name() == _type.Method(j).Name && // 方法名和返回类型名一致时才注入
				mt.Out(0).Kind() == reflect.Ptr && //是指针
				mt.Out(0).Elem().Kind() == reflect.Struct { //是结构体
				instance := _type.Method(j).Func.Call([]reflect.Value{reflect.ValueOf(configs[i])})[0] //_value.Method(j).Call(nil)[0]
				if _, ok := beanMap[reflect.TypeOf(instance.Interface())]; !ok {
					beanMap[reflect.TypeOf(instance.Interface())] = reflect.ValueOf(instance.Interface())
					funcMap[reflect.TypeOf(instance.Interface()).Elem().Name()] = instance.Interface()
				}
			}
		}
	}
}







//------------------以下为测试代码

type ServiceA struct {
	Name      string
	*ServiceB `inject:"ServiceB.Hello()"` // ServiceA.Hello or ServiceB.Hello
	ServiceC
}

func (a *ServiceA) Hello() *ServiceB {
	return &ServiceB{Name: "A多例模式"}
}

type ServiceB struct {
	Name string
}

type ServiceC struct {
	Name string
}

type ServiceD struct {
	*ServiceA
	*ServiceB `inject:"auto"`
	*ServiceC `inject:"ServiceC.Init"`
}

func (b *ServiceB) Hello() *ServiceB {
	return &ServiceB{Name: "多例模式"}
}

type Config struct{}

func (c *Config) ServiceA() *ServiceA { // 返回值与方法名一致
	return &ServiceA{Name: "ServiceA"}
}

func (c *Config) ServiceB() *ServiceB {
	return &ServiceB{Name: "ServiceB"}
}

func (c *Config) ServiceC() *ServiceC {
	return &ServiceC{Name: "ServiceC"}
}

func (*ServiceC) Init() *ServiceC {
	return &ServiceC{Name: "ServiceC-多例"}
}

func (c *Config) ServiceD() *ServiceD {
	return &ServiceD{}
}

func (c *Config) TalkService() *TalkService {
	return &TalkService{}
}

type TalkService struct {
}

func (t *TalkService) Talk() {
	fmt.Println("I am TalkService")
}

func main() {
	cfg := &Config{}
	Configuration(cfg)
	
	//Set(&ServiceA{Name: "ServiceA 你好呀"}, &ServiceB{}, &ServiceC{}, &ServiceD{})
	fmt.Println(Get((*ServiceA)(nil)))
	fmt.Println(Get((*ServiceA)(nil)).ServiceB)
	fmt.Println(Get((*ServiceB)(nil)))
	fmt.Println(Get((*ServiceC)(nil)))
	fmt.Println(Get((*ServiceD)(nil)))
	fmt.Println(Get((*ServiceD)(nil)).ServiceA)
	fmt.Println(Get((*ServiceD)(nil)).ServiceA.ServiceB)
	fmt.Println(Get((*ServiceD)(nil)).ServiceB)
	fmt.Println(Get((*ServiceD)(nil)).ServiceC) //

	fmt.Println()

	if talk := Get((*TalkService)(nil)); talk != nil {
		talk.Talk()
	}

}
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

metabit

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

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

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

打赏作者

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

抵扣说明:

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

余额充值