引言
在“现实世界”中使用任何工具时,如果了解该工具的工作原理,你会更有底气。应用开发也不例外。当你了解开发工具的运作方式时,使用起来会感到更从容、更自信。
本文档的目标是为你提供一份关于 Laravel 框架运行机制的清晰、宏观概述。通过对框架整体有更深入的了解,一切都不再那么“神秘”,你在构建应用时也会更有信心。即便无法立刻理解所有术语,也请不要气馁!先尝试把握基本脉络,随着你探索文档的其他章节,知识会逐步积累。
生命周期概览
起步
所有发往 Laravel 应用的请求,其入口都是 public/index.php 文件。所有请求会由你的 Web 服务器(Apache / Nginx)配置指向该文件。index.php 文件中的代码不多,它只是一个加载框架其余部分的起始点。
index.php 文件会加载由 Composer 生成的自动加载定义,然后从 bootstrap/app.php 中获取 Laravel 应用的一个实例。Laravel 自身执行的第一步,就是创建应用实例/服务容器。
HTTP / 控制台内核
接着,传入的请求会通过应用实例的 handleRequest 或 handleCommand 方法,被分发给 HTTP 内核或控制台内核,具体取决于进入应用的请求类型。这两个内核是所有请求流经的核心位置。现在,我们只关注 HTTP 内核,它是 Illuminate\Foundation\Http\Kernel 的一个实例。
HTTP 内核定义了一个 bootstrappers 数组,这些引导程序会在请求执行前运行。这些引导程序负责配置错误处理、配置日志记录、检测应用环境,以及执行在请求实际处理前需要完成的其他任务。通常,这些类负责 Laravel 的内部配置,你无需操心。
HTTP 内核还负责将请求传递至应用的中间件堆栈。这些中间件负责读写 HTTP 会话、判断应用是否处于维护模式、校验 CSRF 令牌等。我们稍后会详细讨论这些内容。
HTTP 内核 handle 方法的签名很简单:接收一个 Request,返回一个 Response。可以把内核看作一个代表整个应用的“大黑盒”,输入 HTTP 请求,它就会返回 HTTP 响应。
服务提供程序
内核引导过程中最关键的操作之一,是加载应用的服务提供程序。服务提供程序负责引导框架的各个组件,例如数据库、队列、验证和路由组件。
Laravel 会遍历服务提供程序列表,并逐个实例化它们。实例化完成后,会调用所有提供程序的 register 方法。随后,当所有提供程序都完成注册,再逐个调用它们的 boot 方法。这样,服务提供程序在执行 boot 方法时,就能确保所有容器绑定都已注册且可用。
Laravel 提供的几乎所有重要特性,都是由服务提供程序进行引导和配置的。由于服务提供程序要引导并配置框架提供的大量特性,它们是整个 Laravel 引导过程中最核心的环节。
虽然框架内部使用了数十个服务提供程序,你也可以自行创建。可以在 bootstrap/providers.php 文件中找到应用正在使用的用户自定义或第三方服务提供程序列表。
路由
应用完成引导、所有服务提供程序注册完毕后,Request 会被移交给路由器进行分发。路由器会将请求分发到路由或控制器,同时执行与该路由相关的中间件。
中间件提供了一种便捷机制,用于过滤或检查进入应用的 HTTP 请求。例如,Laravel 内置了一个中间件,用于验证应用用户是否已通过身份认证。若用户未认证,该中间件会将用户重定向到登录界面;若用户已认证,中间件则允许请求继续进入应用。有些中间件会作用于应用内的所有路由,例如 PreventRequestsDuringMaintenance,而有些中间件只作用于特定路由或路由组。阅读完整的中间件文档,可以进一步了解中间件。
如果请求通过了匹配路由上配置的所有中间件,就会执行对应的路由或控制器方法,该方法返回的响应会沿路由的中间件链原路返回。
收尾
一旦路由或控制器方法返回响应,响应会沿路由的中间件原路向外传递,让应用有机会修改或检查返回的响应。
最后,当响应传回中间件后,HTTP 内核的 handle 方法会将响应对象返回给应用实例的 handleRequest,该方法随后调用返回响应上的 send 方法。send 方法会将响应内容发送到用户的浏览器。至此,我们就完成了对 Laravel 整个请求生命周期的梳理!
聚焦服务提供程序
服务提供程序确实是引导 Laravel 应用的关键。应用实例被创建、服务提供程序被注册,请求被交给完成引导的应用。就是这么简单!
牢牢掌握 Laravel 应用如何通过服务提供程序进行构建和引导,价值极大。你应用的用户自定义服务提供程序存放在 app/Providers 目录中。
默认情况下,AppServiceProvider 的内容相当少。这个提供程序是添加应用自身引导逻辑和服务容器绑定的理想位置。对于大型应用,你可能需要创建多个服务提供程序,每个提供程序针对应用使用的特定服务,进行更细粒度的引导。