link##_DECLARE(ret) ns##_run_##name args; \
APR_IMPLEMENT_HOOK_GET_PROTO(ns,link,name); \
typedef struct ns##_LINK_##name##_t \
{ \
ns##_HOOK_##name##_t *pFunc; \
const char *szName; \
const char * const *aszPredecessors; \
const char * const *aszSuccessors; \
int nOrder; \
} ns##_LINK_##name##_t;
从上面的定义可以看出,该宏定义冗长,而且事实上,Apache中的关于挂钩定义的每个宏都是很长的。分析颇为费力。在该宏中出现最多的符号当之不让的就是“##”。##宏主要用来实现连接前后的字符串。
APR_DECLARE_EXTERNAL_HOOK宏展来后实现了五个子功能的定义,这几个功能我们分别介绍,其所用的示例则是配置模块的post_config挂钩,在Http_config.中Apache定义了post_config挂钩如下:
AP_DECLARE_HOOK(int,post_config,(apr_pool_t *pconf,apr_pool_t *plog, apr_pool_t *ptemp,server_rec *s)),该宏进一步替换展开后为
APR_DECLARE_EXTERNAL_HOOK(ap,AP,int,post_config, (apr_pool_t *pconf,apr_pool_t *plog, apr_pool_t *ptemp,server_rec *s)),在该宏中:
(1)、typedef ret ns##_HOOK_##name##_t args;
该宏主要用来定义对应的post_config的挂钩的执行函数原型,比如post_config挂钩执行函数原型定义则是:
typedef int ap_HOOK_post_config_t (apr_pool_t *pconf,apr_pool_t *plog,apr_pool_t *ptemp,server_rec *s);
(2)、link##_DECLARE(void) ns##_hook_##name(ns##_HOOK_##name##_t *pf, \
const char * const *aszPre, \
const char * const *aszSucc, int nOrder); \
该宏则用来定义指定挂钩的函数原型,其中ns##_HOOK_##name##_t *pf则是前面定义了对应于该挂钩的执行函数指针,这个函数最终会加入到在请求处理期间的指定时刻进行调用的列表中,而aszPre和aszSucc在形式和功能上都很相近,都是以NULL为结束符的字符串数组,比如{“mod_mime.c”,NULL}。aszPre数组会为这个挂钩规定必须在这个函数之前调用的函数模块,而aszSucc则是规定必须在这个函数之后进行调用的函数模块。上面的post_config挂钩其定义展开后如下:
AP_DECLARE(void) ap_hook_post_config(ap_HOOK_post_config* pf;
const char * const *aszPre,
const char * const *aszSucc,
int nOrder);
函数的第四个参数nOrder则是该挂钩的综合排序参数,整数类型。该整数代表了这个函数与所有的其余同一阶段的其他函数相比较时候的综合位置。如果这个数值越低,则这个挂钩函数将在列表中排列越靠前,因此也越早被调用。如果两个模块为它们的模块设定相同的nOrder,而且模块之间没有依赖关系,则它们的调用顺序则不确定。针对这个参数,Apache提供了5个通用的宏:APR_HOOK_REALLY_FIRST、APR_HOOK_FIRST、APR_HOOK_MIDDLE、APR_HOOK_LAST、APR_HOOK_REALLY_LAST,其定义如下:
#define APR_HOOK_REALLY_FIRST (-10)