路由的加载

未匹配的标注

简介#

上一章,我们说过,在 Laravel 启动引导中,BootProviders 类的根本,就是调用 app.php 配置文件中服务类的 boot 方法。这一章我们就 App\Providers\RouteServiceProvider 这个服务类的 boot 方法进行解析。为什么要重点说这个类的 boot 方法呢,因为这个 boot 方法,就对我们在 web.phpapi.php 中路由进行解析,并存入 Route 类服务实体中,最终绑定到 Application 容器实体中,为请求 URL 进行控制器和方法匹配,从而执行我们定义的方法。

正文#

先看一下 App\Providers\RouteServiceProviderboot 方法

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 方法也是,我们看一下结果图

file

最后 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 服务实体中。

本篇如有错误、不当或者需补充的内容,请各位同僚多提宝贵意见。

本文章首发在 LearnKu.com 网站上。

上一篇 下一篇
《L04 微信小程序从零到发布》
从小程序个人账户申请开始,带你一步步进行开发一个微信小程序,直到提交微信控制台上线发布。
《G01 Go 实战入门》
从零开始带你一步步开发一个 Go 博客项目,让你在最短的时间内学会使用 Go 进行编码。项目结构很大程度上参考了 Laravel。
讨论数量: 0
发起讨论 只看当前版本


暂无话题~