本文介绍了golang不到30行代码实现依赖注入的方法,分享给大家,具体如下:
<强>项目地址强>
go-di-demo
<强>本项目依赖强>
使用标准库实现,无额外依赖
<强>依赖注入的优势强>
用java的人对春天于框架一定不会陌生,春天核心就是一个国际奥委会(控制反转/依赖注入)容器,带来一个很大的优势是解耦的。一般只依赖容器,而不依赖具体的类,当你的类有修改时,最多需要改动一下容器相关代码,业务代码并不受影响。
<强> golang的依赖注入原理强>
总的来说和java的差不多,步骤如下:(golang不支持动态创建对象,所以需要先手动创建对象然后注入,java可以直接动态创建对象)
-
<李>通过反射读取对象的依赖(golang是通过标签实现)李>
<李>在容器中查找有无该对象实例李>
<李>如果有该对象实例或者创建对象的工厂方法,则注入对象或使用工厂创建对象并注入李>
<李>如果无该对象实例,则报错李>
<强>代码实现强>
一个典型的容器实现如下,依赖类型参考了春天的单/原型,分别对象单例对象和实例对象:
包迪 导入( “同步” “反映” “fmt” “弦” “错误” ) var ( ErrFactoryNotFound=错误。新(“未找到的工厂”) ) 接口类型工厂=func()({},错误)//容器 式集装箱结构{ sync.Mutex 单件map [string]接口{} 工厂map [string]工厂 }//容器实例化 func NewContainer容器()* { 返回,容器{ 单例:{})(map [string]接口, 工厂:使(map [string]工厂), } }//注册单例对象 func (p *容器)SetSingleton(名称字符串,单界面{}){ p.Lock () p。单例[名字]=单例 p.Unlock () }//获取单例对象 func (p *容器)GetSingleton(名称字符串)接口{}{ 返回p.singletons[名称] }//获取实例对象 func (p *容器)GetPrototype(名称字符串)(接口{},错误){ 工厂,好:=p.factories[名称] 如果!好{ 返回nil, ErrFactoryNotFound } 返回工厂() }//设置实例对象工厂 func (p *容器)SetPrototype(名称字符串,工厂工厂){ p.Lock () p。工厂[名字]=工厂 p.Unlock () }//注入依赖 func (p *容器)保证({})实例接口错误{ elemType:=reflect.TypeOf(实例).Elem () 避署:=reflect.ValueOf(实例).Elem () 我:=0;我& lt;elemType.NumField ();我+ +{//遍历字段 fieldType:=elemType.Field(我) 标签:=fieldType.Tag.Get (di)//获取标签 diName:=p.injectName(标签) 如果diName==" { 继续 } var ( diInstance接口{} 犯错的错误 ) 如果p.isSingleton(标签){ diInstance=p.GetSingleton (diName) } 如果p.isPrototype(标签){ diInstance呃=p.GetPrototype (diName) } 如果犯错!=nil { 返回错 } 如果diInstance==nil { 返回错误。新(diName +“依赖未找到”) } ele.Field(我)这里(reflect.ValueOf (diInstance)) } 返回nil }//获取需要注入的依赖名称 func (p *容器)injectName字符串(标记字符串){ 标签:=字符串。分割(标签,",") 如果len(标签)==0 { 返回" } 返回标签[0] }//检测是否单例依赖 func (p *容器)isSingleton(标记字符串)bool { 标签:=字符串。分割(标签,",") _,名字:=范围标记{ 如果name==霸汀眥 返回假 } } 还真 }//检测是否实例依赖 func (p *容器)isPrototype(标记字符串)bool { 标签:=字符串。分割(标签,",") _,名字:=范围标记{ 如果name==霸汀眥 还真 } } 返回假 }//打印容器内部实例 func (p *容器)字符串String () { 行:=([]字符串,0,len (p.singletons) + len (p.factories) + 2) 行=append(线,“单例:”) 名称、项:=p。单件{ :=fmt。Sprintf (“% s: % x % s”,名字,和项目,reflect.TypeOf(项).String ()) 行=append(线、线) } 行=append(线,“工厂:”) 名称、项:=p。工厂{ :=fmt。Sprintf (“% s: % x % s”,名字,和项目,reflect.TypeOf(项).String ()) 行=append(线、线) } 返回字符串。加入(线、“\ n”) }