当前位置:网站首页>Decomposition of Uber dependency injection into dig source code analysis
Decomposition of Uber dependency injection into dig source code analysis
2022-06-24 15:35:00 【lpxxn】
Last post decompose uber Rely on note to store dig- Use article How to use it dig Code examples to illustrate , This post analysis dig Source code , See how he implements dependency injection .
digThe central idea of realization : All incomingProvideThe function of must have a divisionerrorThe return parameter outside , Return parameters to be used by formal parameters of other functions .
such as Last one In the first example of , A function func() (*Config, error) return Config Another function func(cfg *Config) *log.Logger The formal parameters of use Config
The whole call process
Let's talk about the whole calling process , The specific details are explained a little bit .
Pass it on to Provide The functions in are not called directly ,dig Only these functions will be analyzed , Extract the formal parameters and return parameters of the function , Organize the container structure according to the return parameters ( This will be explained in detail later ). Only when calling Invoke It's only when I'm in the mood
Will query and call according to the formal parameters of the function passed in, and return the function of these parameters . Also with Last one The first example of
There are two in all Provide Method for function registration
c.Provide(func() (*Config, error)) c.Provide(func(cfg *Config) *log.Logger)
call Invoke Method c.Invoke(func(l *log.Logger)),Invoke Method , By analyzing the formal parameters of the input function , The formal parameter has *log.Logger Go to the container and find out which function's return type has *log.Logger, Find a way func(cfg *Config) *log.Logger,
We found that this function has formal parameters cfg *Config And then go to the return parameter, which has *Config Function of , eureka func() (*Config, error) The formal parameter is empty , Stop querying , Make function calls , The return of *Config Pass to func(cfg *Config) *log.Logger, Conduct
Method call and return *log.Logger Pass to c.Invoke(func(l *log.Logger)) Call and execute functions
So I'm writing Prvoide When registering functions , It's OK to write the order casually , as long as Invoke When you can find the corresponding function, you can .
The above briefly describes the process , Ask a question : If it is a group parameter , such as Last one - Group example Only multiple functions return StudentList []*Studentgroup:"stu,flatten", stay Invoke How to deal with ?
Leave a button first , The following will be explained in detail .
Analyze the incoming function
Provide Add functions to the container ,dig Will analyze the incoming function ,
utilize go The reflection mechanism of , Extract the formal parameters and return parameters of the function to form a node, The picture below is node Detailed description of all fields
Let's look at the formal parameters paramList And return parameters resultList Two fields
paramList
All the formal parameter information of a function will be put into paramList in
type param interface {
fmt.Stringer
// Build all dependent functions , The call returns the value of the function
Build(containerStore) (reflect.Value, error)
// It's generating dot Use when file
DotParam() []*dot.Param
}Build Method is a very important method , He builds all the dependent functions , The call returns the value of the function , Like injection functions c.Provide(func(cfg *Config) *log.Logger) The parameter of cfg *Config It will be resolved to paramList An element of , Calling Build When the method is used ,
I'll go to the container and find out if there's a return *log.Logger Of the injection function node Information , Call again node Of Call Method .
There are several types of formal parameters
paramSingle
paramSingle A good understanding , General formal parameters of injection functions, such as int、string、struct、slice All belong to paramSingle
paramGroupedSlice
paramGroupedSlice Group type , Like the example in the last post
container.Provide(NewUser("tom", 3), dig.Group("stu"))
and
StudentList []*Student `group:"stu"`It's all group types .
paramObject
paramObject The embedded dig.In The type of structure , Like the example in the last post
type DBInfo struct {
dig.In
PrimaryDSN *DSN `name:"primary"`
SecondaryDSN *DSN `name:"secondary"`
}paramObject Can contain paramSingle and paramGroupedSlice type .
resultList
type result interface {
// Extracts the values for this result from the provided value and
// stores them into the provided containerWriter.
Extract(containerWriter, reflect.Value)
// Generate dot File time call
DotResult() []*dot.Result
}Extract(containerWriter, reflect.Value) Extract the corresponding type from the container and assign it a value , Like injection functions c.Provide(func(cfg *Config) *log.Logger) Of *log.Logger It's a resultSingle, Calling Extract It's just to put reflect.Value Give him the value of .
There are several types of return parameters
resultList
node All the return parameters of are saved in resultList in
resultSingle
resultSingle A single return parameter , General return parameters of the injection function, such as int、string、struct、slice All belong to him
resultGrouped
resultGrouped Group type
Like in the last post
container.Provide(NewUser("tom", 3), dig.Group("stu"))
and
StudentList []*Student `group:"stu"`resultObject
resultObject The embedded dig.Out The type of structure , In the last example
type DSNRev struct {
dig.Out
PrimaryDSN *DSN `name:"primary"`
SecondaryDSN *DSN `name:"secondary"`
}resultObject Can contain resultSingle and resultGrouped
Containers
Calling container := dig.New() A container will be created when it is created , all Provide The registered functions will form the node of the container node,node Make up the ` The core of the container
type Container struct {
providers map[key][]*node
nodes []*node
values map[key]reflect.Value
groups map[key][]reflect.Value
rand *rand.Rand
isVerifiedAcyclic bool
deferAcyclicVerification bool
invokerFn invokerFn
}providers map[key][]*node This key It's a very important parameter , He is node The return value of the corresponding function
type key struct {
t reflect.Type
// Only one of name or group will be set.
name string
group string
}name Name the parameters and group Groups cannot exist at the same time , As I said in the last code example .
Look at this code
case resultSingle:
k := key{name: r.Name, t: r.Type}
cv.keyPaths[k] = path
// .......
case resultGrouped:
k := key{group: r.Group, t: r.Type}
cv.keyPaths[k] = path
} Among them t: r.Type Is the type of the return value parameter , That is to say providers map[key][]*node This dictionary ,key Is the return value information []*node Is the function that provides the return value , Why is it a slice, Because return values like groups are provided by multiple functions .
Here's how the group does it , Also answer the questions left above , Our sample code
type Rep struct {
dig.Out
StudentList []*Student `group:"stu,flatten"`
}
if err := container.Provide(NewUser("tom", 3)); err != nil {
t.Fatal(err)
}
if err := container.Provide(NewUser("jerry", 1)); err != nil {
t.Fatal(err)
There are multiple functions that return []*Student,dig It will be resolved into
key{name: "stu", t: Type of Type}, As a dictionary key, There are two Provide The injection function in ,
Calling Extract When the method is used , to groups map[key][]reflect.Value assignment
func (rt resultGrouped) Extract(cw containerWriter, v reflect.Value) {
if !rt.Flatten {
cw.submitGroupedValue(rt.Group, rt.Type, v)
return
}
for i := 0; i < v.Len(); i++ {
cw.submitGroupedValue(rt.Group, rt.Type, v.Index(i))
}
}
func (c *Container) submitGroupedValue(name string, t reflect.Type, v reflect.Value) {
k := key{group: name, t: t}
c.groups[k] = append(c.groups[k], v)
}边栏推荐
- 07. Tencent cloud IOT device side learning - Data Template
- openinstall携手书链:助力渠道数据分析,共创书联网时代
- Es search content top
- 测试 H5 和小程序的区别,你真的知道吗?
- Bitmap of redis data structure
- List of PostgreSQL
- 股票开户要找谁?在线开户安全么?
- FPGA based analog I ² C protocol system design (Part I)
- Linux记录-4.22 MySQL5.37安装(补充)
- R语言实战应用精讲50篇(二十三)-贝叶斯理论重要概念: 可信度Credibility, 模型Models, 和参数Parameters
猜你喜欢
Record the range of data that MySQL update will lock

【我的OpenGL学习进阶之旅】OpenGL的坐标系的学习笔记

Multimeter resistance measurement diagram and precautions

为什么企业实施WMS仓储管理系统很容易失败

Stm32f1 and stm32cubeide programming examples -ws2812b full color LED driver (based on spi+dma)
![[bitbear story collection] June MVP hero story | technology practice collision realm thinking](/img/b7/ca2f8cfb124e7c68da0293624911d1.png)
[bitbear story collection] June MVP hero story | technology practice collision realm thinking

ES mapping之keyword;term查詢添加keyword查詢;更改mapping keyword類型

From pair to unordered_ Map, theory +leetcode topic practice
An accident caused by a MySQL misoperation, and the "high availability" cannot withstand it!

Laravel8 uses faker to call factory to fill data
随机推荐
Oracle RAC configuration multipathing
Mots clés pour la cartographie es; Ajouter une requête par mot - clé à la requête term; Changer le type de mot - clé de cartographie
高速公路服务区智能一体机解决方案
Stm32f1 and stm32cubeide programming examples -ws2812b full color LED driver (based on spi+dma)
The security market has entered a trillion era, and the security B2B online mall system has been accurately connected to deepen the enterprise development path
leetcode 139. Word break word split (medium)
Cloud + community [play with Tencent cloud] essay solicitation activity winners announced
Linux记录-4.22 MySQL5.37安装(补充)
Alibaba OSS object storage service
CVPR2022 | 可精简域适应
Monitoring and warning | is the website attacked?
Es search content top
Design of vga/lcd display controller system based on FPGA (Part 2)
practice
This website teaches you to imitate more than 100 well-known websites!
Typescript raw data type
List of PostgreSQL
Task priority motion planning of floating base
入行 4 年,跳槽 2 次,我摸透了软件测试这一行
Laravel 8 realizes auth login