xiaohuilam / laravel

Laravel 深入详解 —— 源代码解析,新手进阶指南
433 stars 80 forks source link

02. HTTP Kernel Handle 解析 #2

Open xiaohuilam opened 6 years ago

xiaohuilam commented 6 years ago

Kernel Handle

App\Http\Kernel 继承自 Illuminate\Foundation\Http\Kernel 类,所以本文章的分析主要集中在 app/Http/Kernel.phpvendor/laravel/framework/src/Illuminate/Foundation/Http/Kernel.php 两个类中

__construct 解析

因为 App\Http\Kernel 没有 construct 方法,所以穿透到了 Illuminate\Foundation\Http\Kernelconstruct: https://github.com/xiaohuilam/laravel/blob/d081c918b7e582ec5b3f94316f44834466cec37d/vendor/laravel/framework/src/Illuminate/Foundation/Http/Kernel.php#L82-L103

首先是此方法传入参数的 __construct(Application $app, Router $router) 声明,这里恰好使用了 Laravel 容器的依赖注入(Dependency Injection,Inversion of Control的一种)设计。具体的在本篇不讲述,可参见本篇末尾的单独分析的链接的文章。

执行到 __construct 时, Illuminate\Foundation\Application 容器会将 Illuminate\Foundation\Application(即应用容器自身)和 Illuminate\Routing\Router 注入到方法内。然后逻辑代码将两个对象赋给 App\Http\Kernel$this 属性中。

然后将 Illuminate\Foundation\Http\Kernel 的 $middlewarePriority 属性 https://github.com/xiaohuilam/laravel/blob/d081c918b7e582ec5b3f94316f44834466cec37d/vendor/laravel/framework/src/Illuminate/Foundation/Http/Kernel.php#L66-L80 赋值给 Illuminate\Routing\Router 的 $middlewarePriority 属性

根据其注释,此属性是强制对 middleward 中间件执行顺序进行排序的作用。

在后面将 App\Http\Kernel 中声明的 $middlewareGroup https://github.com/xiaohuilam/laravel/blob/d081c918b7e582ec5b3f94316f44834466cec37d/app/Http/Kernel.php#L24-L44Illuminate\Foundation\Http\Kernel 的 96-98行,调用 Illuminate\Routing\Router 的 middlewareGroup 方法,存到 $router 的 $middlewareGroup 中 https://github.com/xiaohuilam/laravel/blob/d081c918b7e582ec5b3f94316f44834466cec37d/vendor/laravel/framework/src/Illuminate/Routing/Router.php#L854-L866

紧接着,将 https://github.com/xiaohuilam/laravel/blob/d081c918b7e582ec5b3f94316f44834466cec37d/app/Http/Kernel.php#L46-L63 的中间件,调用 Illuminate\Routing\Router 的 aliasMiddleware 的方法,绑定到 $router 的 $middleware 中 https://github.com/xiaohuilam/laravel/blob/d081c918b7e582ec5b3f94316f44834466cec37d/vendor/laravel/framework/src/Illuminate/Routing/Router.php#L819-L831

至此, Kernel::__construct() 解析完毕。

handle 解析

https://github.com/xiaohuilam/laravel/blob/d081c918b7e582ec5b3f94316f44834466cec37d/vendor/laravel/framework/src/Illuminate/Foundation/Http/Kernel.php#L105-L132 调用到 Symfony\Component\HttpFoundation\Request 的 enableHttpMethodParameterOverride 方法

Illuminate\Http\Request 继承自 Symfony\Component\HttpFoundation\Request
并且 Illuminate\Http\Request 未覆盖 enableHttpMethodParameterOverride

https://github.com/xiaohuilam/laravel/blob/d081c918b7e582ec5b3f94316f44834466cec37d/vendor/symfony/http-foundation/Request.php#L638-L652

然后,调用 Illuminate\Foundation\Http\Kernel 的 sendRequestThroughRouter https://github.com/xiaohuilam/laravel/blob/d081c918b7e582ec5b3f94316f44834466cec37d/vendor/laravel/framework/src/Illuminate/Foundation/Http/Kernel.php#L134-L152

通过第142行,将 $request 注入进 Illuminate\Foundation\Application 容器。

144行,将门面类中的 request 数据清理掉 https://github.com/xiaohuilam/laravel/blob/d081c918b7e582ec5b3f94316f44834466cec37d/vendor/laravel/framework/src/Illuminate/Support/Facades/Facade.php#L164-L173

Bootstrap 解析

然后146行,调用 Illuminate\Foundation\Http\Kernel 的 bootstrap 方法 https://github.com/xiaohuilam/laravel/blob/d081c918b7e582ec5b3f94316f44834466cec37d/vendor/laravel/framework/src/Illuminate/Foundation/Http/Kernel.php#L154-L164

第161执行到容器的 hasBeenBootstrapped 方法 https://github.com/xiaohuilam/laravel/blob/d081c918b7e582ec5b3f94316f44834466cec37d/vendor/laravel/framework/src/Illuminate/Foundation/Application.php#L249-L257

第162实际得到这个数组 https://github.com/xiaohuilam/laravel/blob/d081c918b7e582ec5b3f94316f44834466cec37d/vendor/laravel/framework/src/Illuminate/Foundation/Http/Kernel.php#L31-L43 然后将数组做为参数,执行容器的 bootstrapWith 方法 https://github.com/xiaohuilam/laravel/blob/d081c918b7e582ec5b3f94316f44834466cec37d/vendor/laravel/framework/src/Illuminate/Foundation/Application.php#L193-L210

特别留意206行的 make 调用

关于容器 make 方法的细节 请查阅 10. 容器的 singleton 和 bind 的实现 的 “揭开 Container::make() 神秘的面纱” 段落

https://github.com/xiaohuilam/laravel/blob/d081c918b7e582ec5b3f94316f44834466cec37d/vendor/laravel/framework/src/Illuminate/Foundation/Application.php#L716-L734 关于 loadDeferredProvider 的逻辑会最终执行到 https://github.com/xiaohuilam/laravel/blob/d081c918b7e582ec5b3f94316f44834466cec37d/vendor/laravel/framework/src/Illuminate/Foundation/Application.php#L691-L714 第710行的 booting 方法,是登记一个闭包 (并不会马上执行这个闭包), 然后这个服务提供者在 boot() 阶段的 $this->fireAppCallbacks($this->bootingCallbacks) 才会真正被创建。 关联阅读请见 04. ServiceProvider Boot 解析

然后结果就是依次执行

这些 Bootstrap 类的 bootstrap 方法

https://github.com/xiaohuilam/laravel/blob/d081c918b7e582ec5b3f94316f44834466cec37d/vendor/laravel/framework/src/Illuminate/Foundation/Bootstrap/LoadEnvironmentVariables.php#L13-L35 https://github.com/xiaohuilam/laravel/blob/d081c918b7e582ec5b3f94316f44834466cec37d/vendor/laravel/framework/src/Illuminate/Foundation/Bootstrap/LoadConfiguration.php#L14-L52 https://github.com/xiaohuilam/laravel/blob/d081c918b7e582ec5b3f94316f44834466cec37d/vendor/laravel/framework/src/Illuminate/Foundation/Bootstrap/HandleExceptions.php#L22-L43 https://github.com/xiaohuilam/laravel/blob/d081c918b7e582ec5b3f94316f44834466cec37d/vendor/laravel/framework/src/Illuminate/Foundation/Bootstrap/RegisterFacades.php#L12-L28 https://github.com/xiaohuilam/laravel/blob/d081c918b7e582ec5b3f94316f44834466cec37d/vendor/laravel/framework/src/Illuminate/Foundation/Bootstrap/RegisterProviders.php#L9-L18 https://github.com/xiaohuilam/laravel/blob/d081c918b7e582ec5b3f94316f44834466cec37d/vendor/laravel/framework/src/Illuminate/Foundation/Bootstrap/BootProviders.php#L9-L18

上面列出的清单中,分别作用为

作用
\Illuminate\Foundation\Bootstrap\LoadEnvironmentVariables 加载环境变量
\Illuminate\Foundation\Bootstrap\LoadConfiguration 加载config
\Illuminate\Foundation\Bootstrap\HandleExceptions 错误处理者
\Illuminate\Foundation\Bootstrap\RegisterFacades 注册门面类
\Illuminate\Foundation\Bootstrap\RegisterProviders 注册服务提供者
\Illuminate\Foundation\Bootstrap\BootProviders 启动服务提供者

其中最后两项在 laravel 请求的生命周期中是至关重要的,我们将在后续文章中重点讲解。

bootstrap 阶段结束后,Kernel::sendRequestThroughRouter 后面带 pipeline 关键字的代码就是管道。

关于管道请查阅 05. Pipeline 解析

https://github.com/xiaohuilam/laravel/blob/d081c918b7e582ec5b3f94316f44834466cec37d/vendor/laravel/framework/src/Illuminate/Foundation/Http/Kernel.php#L148-L151

在进入管道前, 调用了 dispatchToRouter 返回一个闭包对象 https://github.com/xiaohuilam/laravel/blob/d081c918b7e582ec5b3f94316f44834466cec37d/vendor/laravel/framework/src/Illuminate/Foundation/Http/Kernel.php#L166-L178

匹配路由的逻辑清晰可见 https://github.com/xiaohuilam/laravel/blob/d081c918b7e582ec5b3f94316f44834466cec37d/vendor/laravel/framework/src/Illuminate/Routing/Router.php#L601-L682

如果一路抽丝剥茧,我们便能找到 Router 调用 controller 的逻辑了。 请见06. RouteServiceProvider 详解 最后段落。