Open xiaohuilam opened 5 years ago
在 RouteServiceProvider::boot 阶段,所有路由都只是执行登记,匹配的逻辑是在 02. HTTP Kernel Handle解析 的 dispatchToRouter 阶段。
RouteServiceProvider::boot
我们先找到 RouteServiceProvider.php
RouteServiceProvider.php
在 config/app.php 的 providers 中定义的 RouteServiceProvider 其实是: https://github.com/xiaohuilam/laravel/blob/6d9215c0a48aa68ef65d83c3ab8d1ba3c4e23d39/config/app.php#L161 而这个类其实继承自 Illuminate\Foundation\Support\Providers\RouteServiceProvider https://github.com/xiaohuilam/laravel/blob/6d9215c0a48aa68ef65d83c3ab8d1ba3c4e23d39/app/Providers/RouteServiceProvider.php#L6-L9
config/app.php
providers
Illuminate\Foundation\Support\Providers\RouteServiceProvider
我们分析 Illuminate\Foundation\Support\Providers\RouteServiceProvider 的代码
其 register 方法是空的 https://github.com/xiaohuilam/laravel/blob/d081c918b7e582ec5b3f94316f44834466cec37d/vendor/laravel/framework/src/Illuminate/Foundation/Support/Providers/RouteServiceProvider.php#L81-L89
register
而在 boot 阶段,几乎运行了 RouteServiceProvider 中的所有方法 https://github.com/xiaohuilam/laravel/blob/d081c918b7e582ec5b3f94316f44834466cec37d/vendor/laravel/framework/src/Illuminate/Foundation/Support/Providers/RouteServiceProvider.php#L24-L43
boot
RouteServiceProvider
https://github.com/xiaohuilam/laravel/blob/d081c918b7e582ec5b3f94316f44834466cec37d/vendor/laravel/framework/src/Illuminate/Foundation/Support/Providers/RouteServiceProvider.php#L45-L55
Illuminate\Foundation\Application::routesAreCached, 其实就是判断文件 bootstrap/cache/routes.php 是否存在 https://github.com/xiaohuilam/laravel/blob/d081c918b7e582ec5b3f94316f44834466cec37d/vendor/laravel/framework/src/Illuminate/Foundation/Application.php#L895-L903 https://github.com/xiaohuilam/laravel/blob/d081c918b7e582ec5b3f94316f44834466cec37d/vendor/laravel/framework/src/Illuminate/Foundation/Application.php#L905-L913 存在则直接加载 https://github.com/xiaohuilam/laravel/blob/d081c918b7e582ec5b3f94316f44834466cec37d/vendor/laravel/framework/src/Illuminate/Foundation/Support/Providers/RouteServiceProvider.php#L57-L67
Illuminate\Foundation\Application::routesAreCached
bootstrap/cache/routes.php
https://github.com/xiaohuilam/laravel/blob/d081c918b7e582ec5b3f94316f44834466cec37d/vendor/laravel/framework/src/Illuminate/Foundation/Support/Providers/RouteServiceProvider.php#L69-L79 map 方法在这里 https://github.com/xiaohuilam/laravel/blob/d081c918b7e582ec5b3f94316f44834466cec37d/app/Providers/RouteServiceProvider.php#L31-L43 https://github.com/xiaohuilam/laravel/blob/d081c918b7e582ec5b3f94316f44834466cec37d/app/Providers/RouteServiceProvider.php#L45-L72 这里的 mapWebRoutes 和 mapApiRoutes 是分别将 routes/web.php 和 routes/api.php 用 Route 门面类的 group 加载了一遍。 Route::group 实质运行到的是 Illuminate\Routing\Router::group (关于门面类的文章请见 [TODO]),代码为 https://github.com/xiaohuilam/laravel/blob/d081c918b7e582ec5b3f94316f44834466cec37d/vendor/laravel/framework/src/Illuminate/Routing/Router.php#L356-L416 上面的逻辑是一层层剥开 Route::group 去执行里面的 Route::get / Route::post ... https://github.com/xiaohuilam/laravel/blob/d081c918b7e582ec5b3f94316f44834466cec37d/vendor/laravel/framework/src/Illuminate/Routing/Router.php#L133-L214 不难发现,不管是 GET/POST... 还是 any,都只是调用了 addRoute 将这个路由的属性登记了一下: https://github.com/xiaohuilam/laravel/blob/d081c918b7e582ec5b3f94316f44834466cec37d/vendor/laravel/framework/src/Illuminate/Routing/Router.php#L434-L445 $this->routes 是一个 \Illuminate\Routing\RouteCollection 的集合类,add 由这个方法生成的路由 https://github.com/xiaohuilam/laravel/blob/d081c918b7e582ec5b3f94316f44834466cec37d/vendor/laravel/framework/src/Illuminate/Routing/Router.php#L447-L478
map
mapWebRoutes
mapApiRoutes
Route
Route::group
Illuminate\Routing\Router::group
Route::get
Route::post
addRoute
$this->routes
\Illuminate\Routing\RouteCollection
add
路由登记完成后,就是 Kernel 触发管道层层剥洋葱调用中间件最后触发路由 dispatch (当然,这已经运行到 RouteServiceProvider 的外面了)。
剥洋葱的过程请查阅 05. Pipeline 解析
https://github.com/xiaohuilam/laravel/blob/d081c918b7e582ec5b3f94316f44834466cec37d/vendor/laravel/framework/src/Illuminate/Routing/Router.php#L660-L682
第679行的 $route->run 是至关重要的,调用到了 controller (本质其实是使用 09. 容器的依赖注入机制 将路由方法所依赖参数解析出来,并运行) https://github.com/xiaohuilam/laravel/blob/d081c918b7e582ec5b3f94316f44834466cec37d/vendor/laravel/framework/src/Illuminate/Routing/Route.php#L158-L176
$route->run
RouteServiceProvider 详解
我们先找到
RouteServiceProvider.php
在
config/app.php
的providers
中定义的 RouteServiceProvider 其实是: https://github.com/xiaohuilam/laravel/blob/6d9215c0a48aa68ef65d83c3ab8d1ba3c4e23d39/config/app.php#L161 而这个类其实继承自Illuminate\Foundation\Support\Providers\RouteServiceProvider
https://github.com/xiaohuilam/laravel/blob/6d9215c0a48aa68ef65d83c3ab8d1ba3c4e23d39/app/Providers/RouteServiceProvider.php#L6-L9我们分析
Illuminate\Foundation\Support\Providers\RouteServiceProvider
的代码register() 阶段
其
register
方法是空的 https://github.com/xiaohuilam/laravel/blob/d081c918b7e582ec5b3f94316f44834466cec37d/vendor/laravel/framework/src/Illuminate/Foundation/Support/Providers/RouteServiceProvider.php#L81-L89boot() 阶段
而在
boot
阶段,几乎运行了RouteServiceProvider
中的所有方法 https://github.com/xiaohuilam/laravel/blob/d081c918b7e582ec5b3f94316f44834466cec37d/vendor/laravel/framework/src/Illuminate/Foundation/Support/Providers/RouteServiceProvider.php#L24-L43一. setRootControllerNamespace()
https://github.com/xiaohuilam/laravel/blob/d081c918b7e582ec5b3f94316f44834466cec37d/vendor/laravel/framework/src/Illuminate/Foundation/Support/Providers/RouteServiceProvider.php#L45-L55
二. 判断路由是否缓存过
Illuminate\Foundation\Application::routesAreCached
, 其实就是判断文件bootstrap/cache/routes.php
是否存在 https://github.com/xiaohuilam/laravel/blob/d081c918b7e582ec5b3f94316f44834466cec37d/vendor/laravel/framework/src/Illuminate/Foundation/Application.php#L895-L903 https://github.com/xiaohuilam/laravel/blob/d081c918b7e582ec5b3f94316f44834466cec37d/vendor/laravel/framework/src/Illuminate/Foundation/Application.php#L905-L913 存在则直接加载 https://github.com/xiaohuilam/laravel/blob/d081c918b7e582ec5b3f94316f44834466cec37d/vendor/laravel/framework/src/Illuminate/Foundation/Support/Providers/RouteServiceProvider.php#L57-L67三. 如果没有缓存,则遍历路由
https://github.com/xiaohuilam/laravel/blob/d081c918b7e582ec5b3f94316f44834466cec37d/vendor/laravel/framework/src/Illuminate/Foundation/Support/Providers/RouteServiceProvider.php#L69-L79
map
方法在这里 https://github.com/xiaohuilam/laravel/blob/d081c918b7e582ec5b3f94316f44834466cec37d/app/Providers/RouteServiceProvider.php#L31-L43 https://github.com/xiaohuilam/laravel/blob/d081c918b7e582ec5b3f94316f44834466cec37d/app/Providers/RouteServiceProvider.php#L45-L72 这里的mapWebRoutes
和mapApiRoutes
是分别将 routes/web.php 和 routes/api.php 用Route
门面类的 group 加载了一遍。Route::group
实质运行到的是Illuminate\Routing\Router::group
(关于门面类的文章请见 [TODO]),代码为 https://github.com/xiaohuilam/laravel/blob/d081c918b7e582ec5b3f94316f44834466cec37d/vendor/laravel/framework/src/Illuminate/Routing/Router.php#L356-L416 上面的逻辑是一层层剥开Route::group
去执行里面的Route::get
/Route::post
... https://github.com/xiaohuilam/laravel/blob/d081c918b7e582ec5b3f94316f44834466cec37d/vendor/laravel/framework/src/Illuminate/Routing/Router.php#L133-L214 不难发现,不管是 GET/POST... 还是 any,都只是调用了addRoute
将这个路由的属性登记了一下: https://github.com/xiaohuilam/laravel/blob/d081c918b7e582ec5b3f94316f44834466cec37d/vendor/laravel/framework/src/Illuminate/Routing/Router.php#L434-L445$this->routes
是一个\Illuminate\Routing\RouteCollection
的集合类,add
由这个方法生成的路由 https://github.com/xiaohuilam/laravel/blob/d081c918b7e582ec5b3f94316f44834466cec37d/vendor/laravel/framework/src/Illuminate/Routing/Router.php#L447-L478四. dispatch() -> runRoute() 阶段
路由登记完成后,就是 Kernel 触发管道层层剥洋葱调用中间件最后触发路由 dispatch (当然,这已经运行到 RouteServiceProvider 的外面了)。
https://github.com/xiaohuilam/laravel/blob/d081c918b7e582ec5b3f94316f44834466cec37d/vendor/laravel/framework/src/Illuminate/Routing/Router.php#L660-L682
第679行的
$route->run
是至关重要的,调用到了 controller (本质其实是使用 09. 容器的依赖注入机制 将路由方法所依赖参数解析出来,并运行) https://github.com/xiaohuilam/laravel/blob/d081c918b7e582ec5b3f94316f44834466cec37d/vendor/laravel/framework/src/Illuminate/Routing/Route.php#L158-L176