起因
在《深入理解 Nginx 模块开发与架构解析》一书中提到在 Nginx 中除少量核心代码,其他一切皆为模块。核心模块(NGX_CORE_MODULE)是基础类型的模块,官方核心模块有六个具体模块:ngx_core_module、ngx_errlog_module、ngx_events_module、ngx_openssl_module、ngx_http_module、ngx_mail_module,非模块化的框架代码只需要关注于如何调用六个核心模块。书中并没有说明框架代码如何调用核心模块,以及如何通过核心模块调用具体代码,本文对此进行分析。
如何将模块组织进框架
在 configure 阶段会生成 ngx_modules.c
文件,其中有 ngx_modules
变量包含全部模块(有灵性的想法,不直接在代码中组织模块,通过脚本生成模块关系代码)。在 ngx_init_cycle
(在其中调用 ngx_cycle_modules
初始化模块)函数中使用 ngx_cycle_modules
数组对 cycle
中的模块数组进行初始化。
框架代码如何调用核心模块以及核心模块到业务模块的转换
官方 Nginx 共有五大类型的模块:配置模块、核心模块、事件模块、HTTP 模块、mail 模块,其中配置模块与核心模块这两种类型由 Nginx 的框架代码定义并直接使用。但是事件模块、HTTP 模块、mail 模块不会与框架产生直接关系。事件模块、HTTP 模块、mail 模块在核心模块中各有一个模块作为自己的“代言人”,并在同类模块中有一个作为核心业务与管理功能的模块。
1. 概览
1 | ngx_cycle_t * |
观察上面的代码,可以看到会对所有的核心模块(NGX_CORE_MODULE
类型)调用 create_conf
、ngx_conf_parse
、init_conf
,框架直接调用核心模块并没有调用业务模块。核心模块中 ngx_mail_module
、ngx_http_module
、ngx_openssl_module
、ngx_events_module
、ngx_error_module
模块作为其他模块在核心模块的代理,当框架调用到他们时会在其 commands
数组中指定处理指令,而在其处理指令中会将待处理的指令类型、指令模块修改为具体类型,这是从核心模块到具体业务模块处理的转化,例如如下 ngx_http_module
模块的 ngx_http_block
处理代码:
1 | static char * |
2. 框架如何调用事件模块代理 “ngx_events_module”
1 | static ngx_command_t ngx_events_commands[] = { |
从上面代码中可以看到 ngx_events_module
的具体化接口 ngx_events_module_ctx
并不存在 create_conf
调用,而 ngx_event_init_conf
也仅做了 ngx_events_module
模块存在判断,并未做其他工作。那我们猜测 ngx_events_block
做了事件模块的代理工作,下面分析 ngx_events_block
代码。
1 | pcf = *cf; |
在 ngx_events_block
中会遍历 cycle
中所有 NGX_EVENT_MODULE
模块(注意 ngx_events_module
为核心模块类型,此时为核心模块到事件模块的处理转换,参见上面的代码),并调用模块的 create_conf
接口创建存储配置项的机构体指针。接下来会为所有的事件模块解析配置文件,调用 ngx_conf_parse
解析 NGX_EVENT_MODULE
类型模块感兴趣的配置项。之后对所有的 NGX_EVENT_MODULE
类型模块回调 init_conf
。
ngx_event_core_module
模块作为 NGX_EVENT_MODULE
类型模块的一员,同样会经历上面的步骤:create_conf
、init_conf
接口回调以及指令解析。ngx_event_core_module
定义:
1 | static ngx_str_t event_core_name = ngx_string("event_core"); |
观察 ngx_event_core_module
就可以看到 module_init
、process_init
是切人点,实现事件模块的代理。
3. 总结
与事件模块类似,HTTP 模块、mail 模块也是通过核心模块转换到核心模块的具象化类型进行处理。这样做的好处是,框架关心核心模块,核心模块中有某个具象模块的代理用来从核心模块到具象模块的转变,将复杂的文件分解抽象以模块的方式组织代码。在之后的源码阅读中可以从其核心模块代理开始,逐步转换到业务模块管理者,再跳转到具体的业务模块实现。