3.3.3 创建engine对象
在mainDaemon()运行过程中,flag参数检查完毕之后,Docker随即创建engine对象,代码如下:
eng := engine.New()
Engine是Docker架构中的运行引擎,同时也是Docker运行的核心模块。Engine扮演着Docker Container存储仓库的角色,并且通过Job的形式管理Docker运行中涉及的所有任务。
Engine结构体的定义位于./docker/docker/engine/engine.go#L47-L60,具体代码如下:
type Engine struct { handlers map[string]Handler catchall Handler hack Hack // data for temporary hackery (see hack.go) id string Stdout io.Writer Stderr io.Writer Stdin io.Reader Logging bool tasks sync.WaitGroup l sync.RWMutex // lock for shutdown shutdown bool onShutdown []func() // shutdown handlers }
Engine结构体中最为重要的是handlers属性,handlers属性为map类型,key的类型是string,value的类型是Handler。其中Handler类型的定义位于./docker/docker/engine/engine.go#L23,具体代码如下:
type Handler func(*Job) Status
可见,Handler为一个定义的函数。该函数传入的参数为Job指针,返回为Status状态。
了解完Engine以及Handler的基本知识之后,我们真正进入创建Engine实例的部分,即New()函数的实现,具体代码如下:
func New() *Engine { eng := &Engine{ handlers: make(map[string]Handler), id: utils.RandomString(), Stdout: os.Stdout, Stderr: os.Stderr, Stdin: os.Stdin, Logging: true, } eng.Register("commands", func(job *Job) Status { for _, name := range eng.commands() { job.Printf("%s\n", name) } return StatusOK }) // Copy existing global handlers for k, v := range globalHandlers { eng.handlers[k] = v } return eng }
分析以上代码,从返回结果可以发现,New()函数最终返回一个Engine实例对象。而在代码实现部分,大致可以将其分为三个步骤:
1)创建一个Engine结构体实例eng,并初始化部分属性,如handlers、id、标准输出stdout、日志属性Logging等。
2)向eng对象注册名为commands的Handler,其中Handler为临时定义的函数func(job*Job)Status{},该函数的作用是通过Job来打印所有已经注册完毕的command名称,最终返回状态StatusOK。
3)将变量globalHandlers中定义完毕的所有Handler都复制到eng对象的handlers属性中。
至此,一个基本的Engine对象实例eng已经创建完毕,并实现部分属性的初始化。Docker Daemon启动的后续过程中,仍然会对Engine对象实例进行额外的配置。