代码地址

injector

这是一个依赖注入的库 2020.10.13:目前实现了基本数据类型和*struct的依赖注入,只有singleton

Container

// beans already created and populated
        singletonBeans: make(map[string]interface{}),
        // beans already created but didn't be populated
        earlySingletonBeans: make(map[string]interface{}),
        // bean factory, need to be created
        singletonFactories: make(map[string]func() interface{}),

        // marker for the beans created totally
        singletonInCreation: make(map[string]bool),
        // marker for the beans in population
        singletonAlreadyCreated: make(map[string]bool),

        // marker for population in field counting
        populatedSingletonField: make(map[string]map[string]bool),

singletonBeans 是一级缓存,保存已经初始化和依赖注入完成的对象, 使用singletonInCreation进行标记 earlySingletonBeans 是二级缓存,保存已经初始化但是没有完成依赖注入的对象, 使用singletonAlreadyCreated进行标记 singletonFactories 是三级缓存,保存工厂函数,用于生成bean

依赖注入思路

获取bean的伪代码: 解决了循环依赖

func getBean(beanName string) interface{} {
    //如果在一级或者二级缓存,直接返回bean
    if in the cache(beanName) {
        return bean
    }
    //没有找到bean, 通过工厂方法获取
    // 通过三级缓存的工厂方法获取未完成依赖注入的bean
    // 并把bean添加到二级缓存中,并从三级缓存中删除
    var bean = beanFactory.getBean() //对应于 getSingleton

    // 依赖注入 对应于populateSingleton函数
    for i := 0; i < bean.NumField(); i ++ {
        // 需要使用getBaseTypeDataByTag解析需要注入的数据,包括对象
        if bean is base type {
            bean.Field(i).Set(xxx)
        } else {
            // 获取bean
            bean.Field(i).Set(getBean(field.Name))
        }
    }
    //bean注入完成,将bean添加到一级缓存,并从二级缓存中删除
}

tag 注解

  • resource:name 通过name查找bean
  • autowired:name,type 通过name或者type查找bean,默认name
  • data:100 通过data注解给基本类型赋初值

示例

type B struct {
    Name   string `data:"hsp"`
    Abean  *A     `resource:"a"`
    AAbean *A     `autowired:"type"`
}
type A struct {
    Num   int    `json:"tag" data:"2020"`
    Name  string `data:"Ahsp"`
    Bbean *B     `require:"true" resource:"b"`
    Exist bool   `data:"true"`
    a     int
}

func TestCicurlation(t *testing.T) {
    var con = NewContainer()
    con.Registe("a", func() interface{} {
        return &A{}
    })
    con.Registe("b", func() interface{} {
        return &B{}
    })
    var ainter, err = con.GetBeanByName("a")
    if err != nil {
        fmt.Println(err)
        return
    }
    // fmt.Println(a)
    var sa, ok = ainter.(*A)
    if ok {
        fmt.Printf("ptr of sa is 0x%x, content of sa is %+v\n", uintptr(unsafe.Pointer(sa)), sa)
        fmt.Printf("ptr of sa.Bbean is 0x%x, content of sa.Bbean is %+v\n", uintptr(unsafe.Pointer(sa.Bbean)), sa.Bbean)
    }
}

result:

ptr of sa is 0xc00011bdd0, content of sa is &{Num:2020 Name:Ahsp Bbean:0xc000005120 Exist:true a:0}
ptr of sa.Bbean is 0xc000005120, content of sa.Bbean is &{Name:hsp Abean:0xc00011bdd0 AAbean:0xc00011bdd0}