详解hook

📅 2026/8/6 21:12:41
详解hook
hook一般翻译成“钩子”或“挂钩”。它的核心意思是在某个流程的特定时机预留一个位置让外部代码插进去执行。也可以说原来的流程照常走但在某些关键点会额外调用你挂上去的函数。一、 最直观理解假设一个程序原本流程是开始 读取数据 处理数据 输出结果 结束如果它提供 hook你就可以在某些位置插入自己的逻辑开始 before_read_hook() 读取数据 after_read_hook() 处理数据 before_output_hook() 输出结果 结束你不需要改主流程只要把函数“挂”到对应位置。这就是 hook。二、 一个简单例子比如有一个任务调度器void run_task(Task task) { task.run(); }现在你想在任务运行前后打印日志。最直接的方法是改代码void run_task(Task task) { std::cout before task\n; task.run(); std::cout after task\n; }但如果你不想把日志逻辑写死就可以设计 hook#include functional #include iostream struct SchedulerHooks { std::functionvoid() before_task; std::functionvoid() after_task; }; struct Task { void run() { std::cout task running\n; } }; void run_task(Task task, SchedulerHooks hooks) { if (hooks.before_task) { hooks.before_task(); } task.run(); if (hooks.after_task) { hooks.after_task(); } } int main() { SchedulerHooks hooks; hooks.before_task [] { std::cout before task\n; }; hooks.after_task [] { std::cout after task\n; }; Task task; run_task(task, hooks); }输出before task task running after task这里before_task after_task就是 hook。三、 hook 的本质hook 本质上是一种扩展机制。它允许你在不大改原系统的情况下把额外行为插进去。常见用途日志 监控 调试 权限检查 缓存 统计耗时 修改参数 拦截请求 替换默认行为 错误处理 插件扩展比如函数调用前做检查 函数调用后记录耗时 对象销毁前释放外部资源 网络请求发出前添加 token SQL 执行前打印语句 任务调度前记录状态四、 hook 和 callback 的关系hook和callback很像但语义不完全一样。callback强调我把一个函数传给你之后你调用它。hook强调系统在某个固定时机提供一个挂点我把函数挂上去。也就是说callback 是实现手段hook 是使用场景。例如hooks.before_task [] { std::cout before\n; };这个 lambda 是 callback。它挂在before_task这个时机上所以它也是 hook 函数。五、hook 和事件监听的关系事件监听也可以看成 hook 的一种。比如button.on_click([] { std::cout clicked\n; });这里的on_click就是一个 hook 点。当点击发生时系统调用你注册的函数。事件监听通常是“一对多”的 hook一个事件 多个监听函数比如on_start - hook1, hook2, hook3六、多个 hook 的例子更真实的 hook 系统一般允许注册多个函数#include functional #include vector #include iostream class HookList { public: void add(std::functionvoid() fn) { hooks_.push_back(std::move(fn)); } void run() { for (auto fn : hooks_) { fn(); } } private: std::vectorstd::functionvoid() hooks_; }; int main() { HookList before_start; before_start.add([] { std::cout load config\n; }); before_start.add([] { std::cout init logger\n; }); before_start.add([] { std::cout connect database\n; }); before_start.run(); }输出load config init logger connect database这里before_start就是一个 hook 列表。七、 hook 的常见类型hook 有很多种名字一样但场景不同。生命周期 hook在对象、组件、任务生命周期的某个阶段执行。比如on_init on_start on_stop on_destroy before_run after_run调度器里可能有on_task_create on_task_resume on_task_yield on_task_finish这些可以用来做日志、监控、调试。事件 hook某个事件发生时触发。比如on_click on_message on_connect on_disconnect on_readable on_timeout网络服务器里fd 可读 - on_read fd 可写 - on_write 连接关闭 - on_close拦截 hook / interceptor在原行为前后插入逻辑甚至改变原行为。比如 HTTP 请求请求进入 before_request hook 业务处理 after_response hook 返回响应可以用来做鉴权 限流 日志 压缩 跨域处理 错误包装系统 hook操作系统层面的 hook比如键盘 hook 鼠标 hook 系统调用 hook 动态库函数 hook这类更底层也更危险常用于调试、监控、安全软件也可能被恶意软件滥用。Git hooksGit 里的 hook 是脚本挂点。比如pre-commit commit-msg pre-push post-merge当你执行git commitGit 会在特定时机执行.git/hooks/pre-commit。常见用途提交前跑格式化 提交前跑测试 检查 commit message push 前做校验WebhooksWebhook 是网络版 hook。普通 hook 是程序内部调用函数。Webhook 是某个事件发生后向你配置的 URL 发 HTTP 请求。比如GitHub 有人 push 代码 GitHub 调用你的服务器 URL 你的服务器收到通知后自动部署也就是事件发生 - 发 HTTP 回调React HooksReact 里的useState、useEffect也叫 hooks。例如const [count, setCount] useState(0); useEffect(() { console.log(mounted or updated); }, [count]);这个“Hook”是 React 专门的概念意思和通用 hook 有关系但规则更特殊。八、hook 在调度器里的用法结合你前面问的调度器可以这么理解。一个协程调度器原本流程创建协程 恢复协程 协程 yield 协程等待 I/O 协程结束可以设计这些 hookstruct SchedulerHooks { std::functionvoid(int task_id) on_create; std::functionvoid(int task_id) before_resume; std::functionvoid(int task_id) after_yield; std::functionvoid(int task_id, int fd) on_wait_io; std::functionvoid(int task_id) on_finish; };调度器中调用void resume(Task* task) { if (hooks.before_resume) { hooks.before_resume(task-id); } current task; swapcontext(scheduler_ctx, task-ctx); if (task-finished hooks.on_finish) { hooks.on_finish(task-id); } }这样你可以在不改调度器核心逻辑的情况下给它加日志 追踪 性能统计 调试输出 可视化比如hooks.before_resume [](int id) { std::cout resume task id \n; };九、 hook 的两种风格通知型和拦截型hook 大致可以分成两类。通知型 hook只是告诉你发生了什么不改变原流程。比如on_task_finish(task_id);它只是通知任务结束了适合日志、监控。拦截型 hook可以改变原流程。比如bool before_request(Request req);如果返回false请求就不继续执行。bool before_request(Request req) { if (!req.has_token()) { return false; } return true; }这种 hook 更强也更危险。它可以用于鉴权 过滤 修改参数 短路返回 替换默认行为十、hook 的实现方式在 C 里实现 hook 的方式很多。函数指针比较传统using Hook void (*)(); Hook before_run nullptr; void run() { if (before_run) { before_run(); } }简单但不方便捕获状态。std::function更现代更灵活std::functionvoid() before_run;可以接收普通函数 lambda 成员函数包装 函数对象虚函数面向对象里也常见class Base { public: virtual void before_run() {} virtual void run() 0; virtual void after_run() {} };子类重写class MyTask : public Base { public: void before_run() override { std::cout before\n; } void run() override { std::cout run\n; } };这也可以看作 hook。模板策略编译期 hooktemplate typename Policy class Runner { public: void run() { Policy::before(); // do work Policy::after(); } };性能好但灵活性低一些。动态插桩 / 函数替换更底层的 hook 可能会直接拦截函数调用。比如 Linux 下用LD_PRELOAD替换mallocvoid* malloc(size_t size) { // 记录日志 // 调用真正的 malloc }这类 hook 更接近系统级或运行时级别。十一、 hook 的执行顺序问题如果多个 hook 挂在同一个点上before_start: hook A hook B hook C就要明确顺序。否则可能出现问题。比如hook A 初始化日志系统 hook B 打印日志如果 B 在 A 前面执行日志系统还没初始化就可能出错。所以 hook 系统一般要考虑注册顺序 优先级 是否允许中断后续 hook 异常如何处理例如struct HookItem { int priority; std::functionvoid() fn; };按优先级执行。