02. HTTP Kernel Handle 解析
xiaohuilam opened this issue · comments
Kernel Handle
App\Http\Kernel
继承自 Illuminate\Foundation\Http\Kernel
类,所以本文章的分析主要集中在 app/Http/Kernel.php 和 vendor/laravel/framework/src/Illuminate/Foundation/Http/Kernel.php 两个类中
__construct 解析
因为 App\Http\Kernel
没有 __construct 方法,所以穿透到了 Illuminate\Foundation\Http\Kernel
的 __construct:
首先是此方法传入参数的 __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 属性
赋值给
Illuminate\Routing\Router
的 $middlewarePriority 属性
根据其注释,此属性是强制对 middleward 中间件执行顺序进行排序的作用。
在后面将 App\Http\Kernel
中声明的 $middlewareGroup
Lines 24 to 44 in d081c91
在
Illuminate\Foundation\Http\Kernel
的 96-98行,调用 Illuminate\Routing\Router
的 middlewareGroup 方法,存到 $router 的 $middlewareGroup 中laravel/vendor/laravel/framework/src/Illuminate/Routing/Router.php
Lines 854 to 866 in d081c91
紧接着,将
Lines 46 to 63 in d081c91
的中间件,调用
Illuminate\Routing\Router
的 aliasMiddleware 的方法,绑定到 $router 的 $middleware 中laravel/vendor/laravel/framework/src/Illuminate/Routing/Router.php
Lines 819 to 831 in d081c91
至此, Kernel::__construct()
解析完毕。
handle 解析
laravel/vendor/laravel/framework/src/Illuminate/Foundation/Http/Kernel.php
Lines 105 to 132 in d081c91
调用到
Symfony\Component\HttpFoundation\Request
的 enableHttpMethodParameterOverride 方法
Illuminate\Http\Request
继承自Symfony\Component\HttpFoundation\Request
并且Illuminate\Http\Request
未覆盖 enableHttpMethodParameterOverride
laravel/vendor/symfony/http-foundation/Request.php
Lines 638 to 652 in d081c91
然后,调用 Illuminate\Foundation\Http\Kernel
的 sendRequestThroughRouter
laravel/vendor/laravel/framework/src/Illuminate/Foundation/Http/Kernel.php
Lines 134 to 152 in d081c91
通过第142行,将 $request 注入进 Illuminate\Foundation\Application
容器。
144行,将门面类中的 request
数据清理掉
laravel/vendor/laravel/framework/src/Illuminate/Support/Facades/Facade.php
Lines 164 to 173 in d081c91
Bootstrap 解析
然后146行,调用 Illuminate\Foundation\Http\Kernel
的 bootstrap 方法
laravel/vendor/laravel/framework/src/Illuminate/Foundation/Http/Kernel.php
Lines 154 to 164 in d081c91
第161执行到容器的 hasBeenBootstrapped 方法
laravel/vendor/laravel/framework/src/Illuminate/Foundation/Application.php
Lines 249 to 257 in d081c91
第162实际得到这个数组
然后将数组做为参数,执行容器的
bootstrapWith
方法laravel/vendor/laravel/framework/src/Illuminate/Foundation/Application.php
Lines 193 to 210 in d081c91
特别留意206行的 make
调用
关于容器
make
方法的细节
请查阅 10. 容器的 singleton 和 bind 的实现 的 “揭开 Container::make() 神秘的面纱” 段落
laravel/vendor/laravel/framework/src/Illuminate/Foundation/Application.php
Lines 716 to 734 in d081c91
关于 loadDeferredProvider 的逻辑会最终执行到
laravel/vendor/laravel/framework/src/Illuminate/Foundation/Application.php
Lines 691 to 714 in d081c91
第710行的 booting 方法,是登记一个闭包 (并不会马上执行这个闭包), 然后这个服务提供者在
boot()
阶段的 $this->fireAppCallbacks($this->bootingCallbacks)
才会真正被创建。 关联阅读请见 04. ServiceProvider Boot 解析
然后结果就是依次执行
\Illuminate\Foundation\Bootstrap\LoadEnvironmentVariables
\Illuminate\Foundation\Bootstrap\LoadConfiguration
\Illuminate\Foundation\Bootstrap\HandleExceptions
\Illuminate\Foundation\Bootstrap\RegisterFacades
\Illuminate\Foundation\Bootstrap\RegisterProviders
\Illuminate\Foundation\Bootstrap\BootProviders
这些 Bootstrap 类的 bootstrap 方法
上面列出的清单中,分别作用为
类 | 作用 |
---|---|
\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 解析
laravel/vendor/laravel/framework/src/Illuminate/Foundation/Http/Kernel.php
Lines 148 to 151 in d081c91
在进入管道前, 调用了 dispatchToRouter
返回一个闭包对象
laravel/vendor/laravel/framework/src/Illuminate/Foundation/Http/Kernel.php
Lines 166 to 178 in d081c91
匹配路由的逻辑清晰可见
laravel/vendor/laravel/framework/src/Illuminate/Routing/Router.php
Lines 601 to 682 in d081c91
如果一路抽丝剥茧,我们便能找到 Router 调用 controller 的逻辑了。 请见06. RouteServiceProvider 详解 最后段落。