先上最终效果,一段测试代码:
package wind
import (
"testing"
"reflect"
"fmt"
)
type Person struct {
Name string `@:"Autowired"`
}
func (p *Person) hello() {
fmt.Println("Hello,", p.Name)
}
func TestWind(t *testing.T) {
_type := reflect.TypeOf(Person{})
bf := CreateBeanFactory()
err := bf.RegisterBean(_type)
if err != nil {
fmt.Println(err)
} else if bean, ok := bf.GetBean("Person"); ok {
if p, ok := bean.(Person); ok {
p.hello()
}
}
}
根据上面的代码,可以知道我们自动装配的流程如下:
- 创建BeanFactory
- 获取Person的反射类型,并将其注册到BeanFactory中
- 根据名字获取Bean实例
首先定义BeanFactory和Bean
type Bean struct {
Name string
beanType reflect.Type
}
type BeanFactory struct {
beans map[string]Bean
}
这两个定义很简单,BeanFactory使用一个map存储所以注册的Bean
顺带实现CreateBeanFactory
func CreateBeanFactory() *BeanFactory {
return &BeanFactory{beans: make(map[string]Bean)}
}
实现RegisterBean
func (bf *BeanFactory) RegisterBean(t reflect.Type) (err error) {
if t.Kind() != reflect.Struct {
err = errors.New("argument must be a Struct")
} else {
beanName := t.Name()
bf.beans[beanName] = Bean{Name: beanName, beanType: t}
}
return
}
这里简单解释一下,首先判断传入的反射类型是不是reflect.Struct,如果不是的话直接报错。是的话则创建一个Bean,把它存到map里
实现GetBean
关键来了,Golang不支持注解,我的思路是用Struct Tag存储@Autowired注解,所以我们要扫描注册的BeanType的所有字段的Tag:
func (bf *BeanFactory) GetBean(name string) (ins interface{}, ok bool) {
bean, ok := bf.beans[name]
if ok {
// reflect.New返回的是一个ptr类型的Value,可以用reflect.TypeOf去验证
// 这里调用Elem()可以理解为对一个指针的取值操作
e := reflect.New(bean.beanType).Elem()
// 根据BeanType去扫描Bean的所有字段的Tag
_type := bean.beanType
if numField := _type.NumField(); numField > 0 {
for i := 0; i < numField; i++ {
f := _type.Field(i)
// findAllAnnotations会从Tag中解析出所有名字为"@"的pair
// 比如`@:"Autowired" @:"GetMapping('/get')"`会解析成["Autowired", "GetMapping('/get')"],一个字符串数组
if annos, ok := bf.findAllAnnotations(f.Tag); ok {
for _, anno := range annos {
// 这里就简单的支持一下Autowired注解
if anno == "Autowired" {
switch f.Type.Kind() {
case reflect.String:
// 直接注入固定值
e.Field(i).SetString("Luncert")
default:
fmt.Println("Unknown type")
}
}
}
}
}
}
ins = e.Interface()
}
return
}
到此核心代码就都完成了。
详细代码见Github。
更多关于reflect的知识参考:
Golang Reflect反射
Golang学习笔记(11)——反射