nginx的代码中,除了部分底层的核心代码之外,基本上所有的功能都是通过模块化的方式实现的,这样的设计为nginx的功能拓展提供了极大的灵活性。
nginx的模块贯穿了从启动,运行一直到结束的nginx进程的整个生命周期。实际上,在每个阶段,是由nginx核心以及模块自身的配置共同决定哪些模块可以参与,如何参与到当前阶段的运行中。目前,nginx支持多种类型的模块,它们功能定位各有不同,运行的上下文环境也不同,nginx允许每种类型的模块定义属于自己的接口规范,以满足不同模块的需求,但同时每种模块都要基于统一的规范来实现。这样,使得模块的开发变得更清晰,更规范,降低开发难度,同时也给了模块开发足够的灵活性。那么,nginx是把这两者结合在一起的呢?先看看nginx对于模块的定义(红色字段是必须实现的,其中ctx_index和index由nginx框架自动填写,模块开发者不必设置):
struct ngx_module_s {
ngx_uint_t ctx_index;//模块在所属类型模块中所处的位置
ngx_uint_t index;//模块在所有模块中所处的位置
char *name;//模块名称
ngx_uint_t spare0;//未使用
ngx_uint_t spare1;//未使用
ngx_uint_t version;//未使用
const char *signature;//未使用
void *ctx;//模块上下文,一般保存模块实现的接口规范地址
ngx_command_t *commands;//模块指令列表
ngx_uint_t type;//模块类型
ngx_int_t (*init_master)(ngx_log_t *log);
ngx_int_t (*init_module)(ngx_cycle_t *cycle);
ngx_int_t (*init_process)(ngx_cycle_t *cycle);
ngx_int_t (*init_thread)(ngx_cycle_t *cycle);
void (*exit_thread)(ngx_cycle_t *cycle);
void (*exit_process)(ngx_cycle_t *cycle);
void (*exit_master)(ngx_cycle_t *cycle);
uintptr_t spare_hook0;//以下均未使用
uintptr_t spare_hook1;
uintptr_t spare_hook2;
uintptr_t spare_hook3;
uintptr_t spare_hook4;
uintptr_t spare_hook5;
uintptr_t spare_hook6;
uintptr_t spare_hook7;
}
nginx的所有模块都是以上面的数据结构为模板来实现的,通过这种方式,nginx就把模块的开发规范起来了。nginx的模块一共有7个回调函数,它们分别由不同角色在不同的阶段调用,下面做了个简单的整理。
init_master | 在master进程初始化时调用,目前未使用 |
init_module | 模块初始化。由master进程在执行ngx_init_cycle时调用,早于init_process |
init_process | 初始化worker进程,由worker进程在进程开始工作前调用,晚于init_module |
init_thread | 开启线程模式后才调用,目前未使用 |
exit_thread | 开启线程模式才调用,目前未使用 |
exit_process | 在单进程模式下,由进程在退出时调用;在master-worker模式下,由worker进程在退出时调用 |
exit_master | 在单进程模式下,由进程在退出时调用,在master-worker模式下,由master进程在退出时调用。该函数在exit_process之后被调用 |
模块类型(type) | 配置文件上下文类型(ctx) |
NGX_CORE_MODULE | ngx_core_module_t * |
NGX_HTTP_MODULE | ngx_http_module_t * |
NGX_EVENT_MODULE | ngx_event_module_t * |
NGX_MAIL_MODULE | ngx_mail_module_t * |
NGX_STREAM_MODULE | ngx_stream_module_t * |