ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

【基于 Swoole+Hyperf 的微服务实战】第一周·周四:正式踏入 Hyperf 的世界

【基于 Swoole+Hyperf 的微服务实战】第一周·周四:正式踏入 Hyperf 的世界 今天将正式踏入 Hyperf 的世界。Hyperf 是一个基于 Swoole 的、高性能的协程框架它将之前几天我们手写的各种机制HTTP 服务、协程、依赖注入等进行了企业级的封装和抽象。理解它的骨架和生命周期是后续微服务开发的前提。今日目标使用 Composer 创建 Hyperf 项目并成功启动服务。彻底理解 Hyperf 的骨架目录结构知道每块代码应该放在哪里。搞懂 Hyperf 一次请求的完整生命周期Request → 路由 → 中间件 → 控制器 → Response。能够编写一个自定义路由和控制器并访问成功。观察常驻内存下修改代码后需要手动重启的现象加深对 Swoole 特性的理解。一、环境准备与 Hyperf 安装 (约 1 小时)我们继续使用之前的swoole-course目录和 Docker 容器但今天的内容放在一个全新的 Hyperf 项目中。1. 进入容器并检查环境cdswoole-coursedocker-composeexecswoolebash确认 Swoole 扩展和 PHP 版本php-v# 应为 8.2.xphp-m|grepswoole# 必须有 swooleHyperf 需要一些基础扩展我们的phpswoole/swoole:5.1-php8.2镜像已经全部包含无需额外安装。2. 使用 Composer 创建 Hyperf 项目我们将项目创建在容器内的/var/www/hyperf-app目录由于目录已挂载宿主机也能直接编辑代码。cd/var/wwwcomposercreate-project hyperf/hyperf-skeleton hyperf-app如果网络较慢可先配置 Composer 中国镜像composerconfig-grepo.packagistcomposerhttps://mirrors.aliyun.com/composer/安装过程中会提示一些选项对于第一次体验我们可以全部按回车使用默认值比如数据库选择hyperf/database等后续会用到。如果不想交互可以使用--no-dev选项但建议保留开发依赖。等待安装完成看到success即可。3. 检查项目结构进入项目目录看看生成了什么cdhyperf-appls-la你会看到如下主要目录和文件app/ # 应用核心代码 bin/ # 启动脚本 config/ # 所有配置文件 runtime/ # 运行时日志、缓存 vendor/ # Composer 依赖 .env # 环境变量 composer.json4. 配置环境变量复制默认环境文件cp.env.example .env打开.env确认APP_ENVdev和DB_相关配置今天不用数据库可以不管。关键点Hyperf 默认监听0.0.0.0:9501与之前我们手工创建的 Swoole HTTP 服务器端口一致。二、知识核心Hyperf 骨架与生命周期 (约 1.5 小时)1. Hyperf 与 Swoole 的关系Hyperf 是完全建立在 Swoole 协程之上的。它不替代 Swoole而是提供了依赖注入容器PSR-11AOP 面向切面编程注解机制丰富的协程客户端MySQL、Redis、RPC 等你可以把 Hyperf 看作一个装备精良的“太空舱”而我们周一至周三写的代码好比是“手工打造的火箭零件”。今天我们要钻进去看看内部构造。2. 骨架目录深度剖析目录/文件作用你将放置的内容app/业务核心包含控制器、模型、中间件、自定义注解等控制器Controller、模型Model、中间件Middleware等app/Controller/默认控制器目录所有 HTTP 控制器每个方法对应一个路由config/所有配置文件覆盖框架默认值autoload/下的文件会被自动加载如数据库、Redis、路由配置config/routes.php路由配置文件定义 URL 到控制器的映射config/autoload/dependencies.php依赖注入的绑定关系接口到实现的映射bin/hyperf.php应用启动入口一般不需要修改runtime/日志、缓存、编译后的代理类等所有运行时产生的文件可随时删除vendor/Composer 依赖绝不要手动修改.env环境变量数据库密码、应用密钥等重点config/目录下的配置分为autoload/和其他。autoload/下的配置文件不需要显式引入框架会自动扫描合并。这是 Hyperf 的约定。3. 一次请求的生命周期核心理解这个流程后续开发才能游刃有余。我们以一个访问/index/index的请求为例Swoole HTTP 服务器接收到请求触发onRequest回调。Hyperf 框架核心接管从容器中解析Hyperf\HttpServer\Server。创建协程上下文为该请求创建全新的协程和专属的 Context。路由匹配根据config/routes.php找到对应的控制器和方法。全局中间件执行CoreMiddleware处理请求和响应如解析 JSON 体、设置协程上下文等。路由级中间件按顺序执行可以进行权限校验、日志记录等。控制器方法调用依赖注入容器会自动解析控制器构造函数和方法的参数然后执行。返回响应控制器返回值或Response对象交给 Swoole 的$response-end()。清理协程上下文请求结束协程销毁。图解Request → [路由匹配] → [全局中间件] → [路由中间件1] → [路由中间件2] → [控制器] → Response中间件可以在控制器之前或之后执行通过$handler-handle($request)分割。这个机制我们明天会亲手实践。三、实战启动项目并编写第一个接口 (约 2 小时)1. 启动 Hyperf 服务在项目根目录下执行php bin/hyperf.php start你会看到熟悉的 Swoole 启动信息显示 Worker 进程数、监听端口等。[INFO] Server listening on 0.0.0.0:9501注意如果之前的手写 Swoole 服务器还在运行先CtrlC关闭端口才不会冲突。现在打开浏览器访问http://localhost:9501会看到 Hyperf 的欢迎页面显示 “Hello Hyperf.”。这说明框架已成功运行。2. 分析默认路由与控制器打开config/routes.php?phpuseHyperf\HttpServer\Router\Router;Router::get(/favicon.ico,function(){return;});Router::get(/,function(){returnHello Hyperf.;});可见默认是闭包路由。我们再看看控制器路由的样子被注释掉的Router::get(/hello-hyperf,[App\Controller\IndexController::class,index]);取消这行注释如果存在然后打开app/Controller/IndexController.php?phpdeclare(strict_types1);namespaceApp\Controller;useHyperf\HttpServer\Annotation\Controller;useHyperf\HttpServer\Annotation\RequestMapping;classIndexControllerextendsAbstractController{publicfunctionindex(){$user$this-request-input(user,Hyperf);$method$this-request-getMethod();return[method$method,messageHello{$user}.,];}}注意Hyperf 控制器继承了AbstractController可以直接使用$this-request和$this-response。3. 动手添加一个新路由和控制器我们现在自己创建一个接口。第一步创建控制器app/Controller/UserController.php?phpdeclare(strict_types1);namespaceApp\Controller;classUserControllerextendsAbstractController{publicfunctioninfo(int$id){return[code200,data[id$id,nameSwoole,emailswoolehyperf.io,]];}}第二步在config/routes.php中添加路由在文件最底部// 添加一个 GET 路由带参数Router::get(/user/{id:\d},[App\Controller\UserController::class,info]);4. 测试新接口保存文件后你会发现并没有自动生效。这是因为 Swoole 是常驻内存的代码只在启动时加载。必须重启服务才能看到新代码。回到终端CtrlC停止服务然后重新执行php bin/hyperf.php start。或者使用 Hyperf 的watch热重启后续会学。现在访问curlhttp://localhost:9501/user/123输出{code:200,data:{id:123,name:Swoole,email:swoolehyperf.io}}成功你已经完成了第一个 Hyperf 接口。5. 使用注解路由可选提前感受Hyperf 还支持注解方式定义路由这样不需要修改routes.php。将UserController改成?phpdeclare(strict_types1);namespaceApp\Controller;useHyperf\HttpServer\Annotation\Controller;useHyperf\HttpServer\Annotation\RequestMapping;#[Controller(prefix:/user)]classUserControllerextendsAbstractController{#[RequestMapping(path:info/{id:\d},methods:get)]publicfunctioninfo(int$id){// ...}}然后删除routes.php中对应路由重启服务一样有效。注解是 Hyperf 强大的特性之一我们将在第二周深入学习。四、成果测试与生命周期观察 (约 1 小时)1. 观察常驻内存与变量共享我们做一个小实验来理解常驻内存的影响。修改UserController在类中增加一个静态属性classUserControllerextendsAbstractController{privatestaticint$count0;publicfunctioninfo(int$id){self::$count;return[countself::$count,data[id$id]];}}重启服务用curl连续访问http://localhost:9501/user/1你会看到count依次递增1, 2, 3…{count:1,data:{id:1}} {count:2,data:{id:1}}这说明静态属性在多个请求之间是共享的这就是常驻内存的危险与优势你可以用来做计数器但也要小心全局状态污染。在生产中应该使用协程安全的工具如Context、Redis来存储请求间数据而不是静态变量。2. 生命周期验证追踪中间件和控制器执行Hyperf 提供了非常方便的日志通道我们可以在控制器和未来的中间件中打印日志观察执行顺序。但今天我们可以简单地在app/Controller/IndexController.php的index方法中添加var_dump(Controller executed);然后重启服务访问终端会直接输出。这在实际开发中非常有用。3. 测试清单检验项方法通过标准Hyperf 成功启动php bin/hyperf.php start无报错显示监听 9501欢迎页浏览器访问http://localhost:9501显示 “Hello Hyperf.”自定义路由访问curl http://localhost:9501/user/5返回 JSON 包含用户信息静态变量递增现象连续curl同一接口count 字段每次递增重启后生效修改控制器返回值重启后curl返回修改后的内容热重启缺失修改代码不重启curl返回结果不变证明常驻内存4. 进阶思考与自测问题为什么 Hyperf 启动后修改代码必须重启Swoole 的reload机制是怎样的你会看到bin/hyperf.php start启动的是 Master 和 Manager 进程Worker 进程负责处理请求。修改文件后可以发送SIGUSR1信号给 Manager 实现热重启。Hyperf 提供了php bin/hyperf.php server:watch命令支持文件监听需要额外安装hyperf/watcher组件我们之后会用到。任务尝试在config/autoload/中新建一个custom.php返回一个数组配置并在控制器中通过config(custom.key)读取使用Hyperf\Utils\ApplicationContext或注入ConfigInterface。五、今日作业与学习产出提交代码将整个hyperf-app项目提交到 Git 仓库注意.env不要提交敏感信息可提交.env.example。绘制生命周期图使用流程图工具或手绘画出从 HTTP 请求进入到响应用户的完整过程标注核心中间件、路由、控制器位置。学习笔记记录 Hyperf 骨架目录的作用以及常驻内存带来的优缺点。挑战任务实现一个GET /time接口返回当前服务器时间但要求时间格式通过配置文件config/autoload/custom.php中的time_format项控制。考验你对配置读取的掌握。经过今天的学习你已经能熟练搭建 Hyperf 工程理解其运行机制为明天深入依赖注入、注解、AOP 等核心特性打下了坚实基础。
返回列表