上面的主要逻辑就是首先判断注册的加载函数能不能加载到配置文件 , 如果不能 , 就调用默认加载函数 。
而默认加载函数如下
func defaultLoader(serverType string) (caddy.Input, error) {// caddy.DefaultConfigFile = Corefile contents, err := os.ReadFile(caddy.DefaultConfigFile) return caddy.CaddyfileInput{Contents:contents,Filepath:caddy.DefaultConfigFile,ServerTypeName: serverType, }, nil}
因为本地有Corefile文件, 所以读取并构造CaddyfileInput对象 。
至此配置文件加载完成 。
小结通过代码我们知道配置文件的加载顺序依次是
命令行参数指定的配置文件 > 当前工作目录的Corefile > 静态设置的Corefile内容(".:" + Port + " {nwhoaminlogn}n"))
启动服务再次粘贴一下前面的启动代码:
// 解析配置文件instance, err := caddy.Start(corefile)// 主进程等待退出信号instance.Wait()
基于上一步加载的配置文件开始服务.
代码如下:
func Start(cdyfile Input) (*Instance, error) { inst := &Instance{serverType: cdyfile.ServerType(), wg: new(sync.WaitGroup), Storage: make(map[interface{}]interface{})}// 启动监听进程 err := startWithListenerFds(cdyfile, inst, nil)// 用于重启, 告诉父进程是否重启成功 signalSuccessToParent() // 执行on之类的相关命令, 比如// on startup /etc/init.d/php-fpm start EmitEvent(InstanceStartupEvent, inst) return inst, nil}func startWithListenerFds(cdyfile Input, inst *Instance, restartFds map[string]restartTriple) error { instances = Append(instances, inst)// 验证配置文件并解析 err = ValidateAndExecuteDirectives(cdyfile, inst, false) // 创建Server对象用于后续监听服务 slist, err := inst.context.MakeServers()// 依次调用各个插件注册的启动函数 for _, startupFunc := range inst.OnStartup {err = startupFunc()if err != nil {return err} }// 开始监听 err = startServers(slist, inst, restartFds) started = true return nil}
启动服务大概可以分为两步
- 解析配置文件 加载配置的各个插件并按插件的顺序执行setup函数, 而不是配置文件插件名出现的顺序加载插件
- 启动监听服务
func ValidateAndExecuteDirectives(cdyfile Input, inst *Instance, justValidate bool) error {// dns stypeName := cdyfile.ServerType() // 获取dns的serverType, 在corednsserverregister.go中注册 stype, err := getServerType(stypeName) inst.caddyfileInput = cdyfile // 将配置文件加载成一个个ServerBlock对象 sblocks, err := loadServerBlocks(stypeName, cdyfile.Path(), bytes.NewReader(cdyfile.Body())) // 还是corednsserverregister.go中注册的Context inst.context = stype.NewContext(inst) sblocks, err = inst.context.InspectServerBlocks(cdyfile.Path(), sblocks) return executeDirectives(inst, cdyfile.Path(), stype.Directives(), sblocks, justValidate)}func executeDirectives(inst *Instance, filename string, directives []string, sblocks []caddyfile.ServerBlock, justValidate bool) error { storages := make(map[int]map[string]interface{}) // 最外层的循环是治理 , 所以配置文件的指令顺序不重要 , 重要的代码里面的顺序// 插件的顺序是根据plugin.cfg文件生成的 for _, dir := range directives {for i, sb := range sblocks {var once sync.Once// 依次去serverBlocks中检查是否存在该指令// keys是 .:53, .:1053之类的监听地址for j, key := range sb.Keys {if tokens, ok := sb.Tokens[dir]; ok {controller := &Controller{instance:inst,Key:key,Dispenser: caddyfile.NewDispenserTokens(filename, tokens),OncePerServerBlock: func(f func() error) error {var err erroronce.Do(func() {err = f()})return err},ServerBlockIndex:i,ServerBlockKeyIndex: j,ServerBlockKeys:sb.Keys,ServerBlockStorage:storages[i][dir],}// 因为各个key都是公用同一个ServerBlocks, 所以没比较初始化两遍if j > 0 {continue}// 调用插件的setup方法// 这里只是注册插件 , 还没将插件构造成pluginChainsetup, err := DirectiveAction(inst.serverType, dir)err = setup(controller)}}} } return nil}
解析配置文件的主要工作就是解析配置文件的指令 , 然后根据代码中指令的顺序依次调用对应的setup方法 。setup方法会在自定义插件编写的段落着重介绍 , 这里只需要知道 , setup方法是一个将插件集成到调用链的一个方法就行了 。
至此配置文件解析完成 , 各个插件也加载完成了 。是时候启动服务了
之所以按照插件在代码顺序执行而不是在配置文件中出现的顺序配置 , 这是为了避免一些奇怪的问题 , 比如log和cache放在forward之后缓存和日志就不生效了 , 这会让人很恼火 。启动监听服务启动服务的入口大致如下:
推荐阅读
- 下嘴唇发麻什么病兆
- 2021电视机排行榜前十名 2021最好的电视机
- 虾皮补肾吗
- 右肩关节疼痛的原因
- 后腰部有横纹是肾虚吗
- 如果是你就好了日语歌?如果是你就好了 李正
- 胡萝卜减肥汁
- 如果那天我再勇敢一点作文?那天如果我再勇敢一些的作文600字
- 徐庶最后回到刘备身边了吗?徐庶如果一直辅佐刘备_1
- 如果关羽守荆州?如果关羽守住了荆州