Open xiaohuilam opened 6 years ago
App\Http\Kernel 继承自 Illuminate\Foundation\Http\Kernel 类,所以本文章的分析主要集中在 app/Http/Kernel.php 和 vendor/laravel/framework/src/Illuminate/Foundation/Http/Kernel.php 两个类中
App\Http\Kernel
Illuminate\Foundation\Http\Kernel
因为 App\Http\Kernel 没有 construct 方法,所以穿透到了 Illuminate\Foundation\Http\Kernel 的 construct: 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(Application $app, Router $router)
执行到 __construct 时, Illuminate\Foundation\Application 容器会将 Illuminate\Foundation\Application(即应用容器自身)和 Illuminate\Routing\Router 注入到方法内。然后逻辑代码将两个对象赋给 App\Http\Kernel 的 $this 属性中。
Illuminate\Foundation\Application
Illuminate\Routing\Router
$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-L44 在 Illuminate\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
$middlewareGroup
紧接着,将 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() 解析完毕。
Kernel::__construct()
https://github.com/xiaohuilam/laravel/blob/d081c918b7e582ec5b3f94316f44834466cec37d/vendor/laravel/framework/src/Illuminate/Foundation/Http/Kernel.php#L105-L132 调用到 Symfony\Component\HttpFoundation\Request 的 enableHttpMethodParameterOverride 方法
Symfony\Component\HttpFoundation\Request
Illuminate\Http\Request 继承自 Symfony\Component\HttpFoundation\Request 并且 Illuminate\Http\Request 未覆盖 enableHttpMethodParameterOverride
Illuminate\Http\Request
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
request
然后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
bootstrapWith
特别留意206行的 make 调用
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 解析
boot()
$this->fireAppCallbacks($this->bootingCallbacks)
然后结果就是依次执行
\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 方法
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
上面列出的清单中,分别作用为
其中最后两项在 laravel 请求的生命周期中是至关重要的,我们将在后续文章中重点讲解。
在 bootstrap 阶段结束后,Kernel::sendRequestThroughRouter 后面带 pipeline 关键字的代码就是管道。
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
dispatchToRouter
匹配路由的逻辑清晰可见 https://github.com/xiaohuilam/laravel/blob/d081c918b7e582ec5b3f94316f44834466cec37d/vendor/laravel/framework/src/Illuminate/Routing/Router.php#L601-L682
如果一路抽丝剥茧,我们便能找到 Router 调用 controller 的逻辑了。 请见06. RouteServiceProvider 详解 最后段落。
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: 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-L44 在Illuminate\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 方法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-L173Bootstrap 解析
然后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
调用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 解析然后结果就是依次执行
\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 方法
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
\Illuminate\Foundation\Bootstrap\HandleExceptions
\Illuminate\Foundation\Bootstrap\RegisterFacades
\Illuminate\Foundation\Bootstrap\RegisterProviders
\Illuminate\Foundation\Bootstrap\BootProviders
其中最后两项在 laravel 请求的生命周期中是至关重要的,我们将在后续文章中重点讲解。
在
bootstrap
阶段结束后,Kernel::sendRequestThroughRouter
后面带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