服务提供者初始化引导

未匹配的标注

简介

前面几个章节,我们把如下图前五个引导启动讲解完毕,今天我们就看最后一个:BootProviders

file

正文

  • 首先看 BootProviders 类的 bootstrap 方法

    class BootProviders
    {
      /**
       * Bootstrap the given application.
       *
       * @param  \Illuminate\Contracts\Foundation\Application  $app
       * @return void
       */
      public function bootstrap(Application $app)
      {
          $app->boot();
      }
    }

    很清晰,表面上简简单单调用了容器对象的 boot 方法,那我们就看 boot 方法干了什么吧

  • boot 方法源码如下

    public function boot()
    {
      // 首先判断应用之前有无加载过,如果加载过,直接返回
      if ($this->booted) {
          return;
      }
    
      // 读取 bootingCallbacks 属性数组,调用数组中的回调函数。作用就是执行一系列服务引导前的一些自定义行为
      $this->fireAppCallbacks($this->bootingCallbacks);
    
      // 此行为核心,下面将做详细说明
      array_walk($this->serviceProviders, function ($p) {
          $this->bootProvider($p);
      });
    
      // 将有无加载的开关改为 true ,防止二次加载
      $this->booted = true;
    
      // 执行服务引导后的一些自定义行为
      $this->fireAppCallbacks($this->bootedCallbacks);
    }

    关于上面代码说到的核心

    array_walk($this->serviceProviders, function ($p) {
      $this->bootProvider($p);
    });

    array_walk:官方说明是指使用用户自定义函数对数组中的每个元素做回调处理

    也就是说,将 $this->serviceProviders 数组的每个元素分别当做参数调用后面的闭包函数

  • 我们看一下 $this->serviceProviders 都有什么吧

    file

    一共 19 个服务提供者对象。、

    那么 $this->bootProvider($p); 到底对每个服务提供者对象干了什么呢。其实就是看看这些服务提供者对象有没有 boot 方法,如果有,则执行一下这个方法,如果没有,就跳过,继续处理下一个服务提供者。

  • 下面我先对这 19 个服务提供者简要说明,重点说明它有没有 boot 方法

    • Illuminate\Events\EventServiceProvider : 系统事件服务提供者,就是用来 Application 初始化时绑定 events 别名;没有 boot 方法
    • Illuminate\Log\LogServiceProvider:系统日志服务提供者;没有 boot 方法
    • Illuminate\Routing\RoutingServiceProvider:系统路由服务提供者;没有 boot 方法
    • Illuminate\Auth\AuthServiceProvider:系统用户授权服务提供者;没有 boot 方法
    • Illuminate\Cookie\CookieServiceProvider:系统 Cookie 服务提供者;没有 boot 方法
    • Illuminate\Database\DatabaseServiceProvider:系统数据库服务提供者;boot 方法

    先瞅一眼源码

    public function boot()
    {
        Model::setConnectionResolver($this->app['db']);
    
        Model::setEventDispatcher($this->app['events']);
    }
    • Illuminate\Encryption\EncryptionServiceProvider:系统加解密服务提供者;没有 boot 方法
    • Illuminate\Filesystem\FilesystemServiceProvider:系统文件处理服务提供者;没有 boot 方法
    • Illuminate\Foundation\Providers\FormRequestServiceProvider:系统表单处理服务提供者;boot 方法

    瞅一眼源码

    public function boot()
    {
        $this->app->afterResolving(ValidatesWhenResolved::class, function ($resolved) {
            $resolved->validateResolved();
        });
    
        $this->app->resolving(FormRequest::class, function ($request, $app) {
            $request = FormRequest::createFrom($app['request'], $request);
    
            $request->setContainer($app)->setRedirector($app->make(Redirector::class));
        });
    }
    • Illuminate\Foundation\Providers\FoundationServiceProvider:系统基类服务提供者;没有 boot 方法
    • Illuminate\Notifications\NotificationServiceProvider:系统通知服务提供者;boot 方法

    源码

    public function boot()
    {
        $this->loadViewsFrom(__DIR__.'/resources/views', 'notifications');
    
        if ($this->app->runningInConsole()) {
            $this->publishes([
                __DIR__.'/resources/views' => $this->app->resourcePath('views/vendor/notifications'),
            ], 'laravel-notifications');
        }
    }
    • Illuminate\Pagination\PaginationServiceProvider:系统分页服务提供者:boot 方法

    源码

    public function boot()
    {
        $this->loadViewsFrom(__DIR__.'/resources/views', 'pagination');
    
        if ($this->app->runningInConsole()) {
            $this->publishes([
                __DIR__.'/resources/views' => $this->app->resourcePath('views/vendor/pagination'),
            ], 'laravel-pagination');
        }
    }
    • Illuminate\Session\SessionServiceProvider:系统Session服务提供者:没有 boot 方法
    • Illuminate\View\ViewServiceProvider:系统视图服务提供者:没有 boot 方法
    • Fideloper\Proxy\TrustedProxyServiceProvider:系统可信代理服务提供者:boot 方法
    public function boot()
    {
        $source = realpath($raw = __DIR__.'/../config/trustedproxy.php') ?: $raw;
    
        if ($this->app instanceof LaravelApplication && $this->app->runningInConsole()) {
            $this->publishes([$source => config_path('trustedproxy.php')]);
        } elseif ($this->app instanceof LumenApplication) {
            $this->app->configure('trustedproxy');
        }
    
        if ($this->app instanceof LaravelApplication && ! $this->app->configurationIsCached()) {
            $this->mergeConfigFrom($source, 'trustedproxy');
        }
    }
    • App\Providers\AppServiceProvider:可供用户自行定义应用的服务提供者;boot 方法

    源码是空的,需要你来根据项目实际和官方文档进行添加

    public function boot()
    {
        //
    }
    • App\Providers\AuthServiceProvider:可自行定义的授权服务提供者:boot 方法

    源码

    public function boot()
    {
        $this->registerPolicies();
    
        //
    }
    • App\Providers\EventServiceProvider:可自行定义的事件服务提供者:boot 方法

    源码

    public function boot()
    {
        parent::boot();
    
        //
    }
    • App\Providers\RouteServiceProvider:可自定义的路由服务提供者:boot 方法

    这个服务提供者的 boot 方法就是处理你在 web 或 api 中写的路由,将路由信息绑定到容器中,就是这个 boot 方法所做的,之后我会详细对这块进行说明

    public function boot()
    {
        //
    
        parent::boot();
    }

写在最后

关于那些没有 boot 方法的服务提供者,其实都做了一样的事情,就是作为实际服务实体与容器实体之间的运输车或者桥梁,将服务实体与容器实体绑定在一起,因为这些服务提供者都一个叫 register 方法。。。

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

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

上一篇 下一篇
《L03 构架 API 服务器》
你将学到如 RESTFul 设计风格、PostMan 的使用、OAuth 流程,JWT 概念及使用 和 API 开发相关的进阶知识。
《G01 Go 实战入门》
从零开始带你一步步开发一个 Go 博客项目,让你在最短的时间内学会使用 Go 进行编码。项目结构很大程度上参考了 Laravel。
讨论数量: 0
发起讨论 查看所有版本


暂无话题~