路由的加载

未匹配的标注

简介

上一章,我们说过,在 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 网站上。

上一篇 下一篇
《L02 从零构建论坛系统》
以构建论坛项目 LaraBBS 为线索,展开对 Laravel 框架的全面学习。应用程序架构思路贴近 Laravel 框架的设计哲学。
《G01 Go 实战入门》
从零开始带你一步步开发一个 Go 博客项目,让你在最短的时间内学会使用 Go 进行编码。项目结构很大程度上参考了 Laravel。
讨论数量: 0
发起讨论 只看当前版本


暂无话题~