路由的加载
简介
上一章,我们说过,在 Laravel 启动引导中,BootProviders 类的根本,就是调用 app.php 配置文件中服务类的 boot 方法。这一章我们就 App\Providers\RouteServiceProvider 这个服务类的 boot 方法进行解析。为什么要重点说这个类的 boot 方法呢,因为这个 boot 方法,就对我们在 web.php 或 api.php 中路由进行解析,并存入 Route 类服务实体中,最终绑定到 Application 容器实体中,为请求 URL 进行控制器和方法匹配,从而执行我们定义的方法。
正文
先看一下 App\Providers\RouteServiceProvider 的 boot 方法
public function boot()
{
//
parent::boot();
}
发现调用了父类的 boot 方法,那么我们去看父类
public function boot()
{
// 这一行,从词面不难看出是在设置根控制器命名空间,真实操作是设置 UrlGenerator 类对象中 rootNamespace 属性的值
$this->setRootControllerNamespace();
// 这一行是看 `./bootstrap/cache/routes.php` 缓存文件存在吗,存在的话就直接加载
if ($this->app->routesAreCached()) {
$this->loadCachedRoutes();
} else {
// **这个是路由加载的核心方法
$this->loadRoutes();
// 这一行,还记得上一中的 booted 的,就是全部服务类加载完后的操作;这里就是定义加载完后要执行的回调函数
$this->app->booted(function () {
$this->app['router']->getRoutes()->refreshNameLookups();
$this->app['router']->getRoutes()->refreshActionLookups();
});
}
}
我们接着看 $this->loadRoutes() 这个核心方法
protected function loadRoutes()
{
if (method_exists($this, 'map')) {
$this->app->call([$this, 'map']);
}
}
这段代码,从字面不难看出,就是判断当前对象有没有 map 方法,有的话就执行。注意,当前对象是 App\Providers\RouteServiceProvider 实例化的,所以我们要从这个服务类开看起,不应该直接去看它的父类。经过寻找,map 方法被发现
public function map()
{
$this->mapApiRoutes();
$this->mapWebRoutes();
//
}
哇,好熟悉,这不就是我们可以自行修改或添加自定义路由文件的方法吗。第一行加载 api.php ,第二行加载 web.php
我们以 api.php 来看
protected function mapApiRoutes()
{
Route::prefix('api')
->middleware('api')
->namespace($this->namespace)
->group(base_path('routes/api.php'));
}
执行顺序:调用 Route 门面,从 route 解析出 Route 服务实体,然后调用 prefix 方法,这个方法实际是在 Route 实体对象 attributes 属性中设定 prefix => 'api' 数组键值对。然后调用 middleware 方法也是, namespace 方法也是,我们看一下结果图

最后 group 方法,会携带上面的 attributes 属性去执行 web.php 文件,如下
protected function loadRoutes($routes)
{ // $routes = 'D:/www/learn/routes/api.php'
if ($routes instanceof Closure) {
$routes($this);
} else {
$router = $this;
require $routes;
}
}
会包含执行 api.php,将路由绑定的 Route 服务实体中。
本篇如有错误、不当或者需补充的内容,请各位同僚多提宝贵意见。
Laravel 之道
关于 LearnKu
推荐文章: