注册服务

未匹配的标注

简介

这一章,我们来看一下引导程序中的注册服务。

file

  • 先了解一下这个注册服务干了什么:

    首先,对 app.php 配置文件中 providers 数组内的服务器提供者进行分类,分为主要的三类: deferred 延时加载、eager 即时加载、when 事件触发。

    分类依据是看这个服务器提供者中 $defer 属性的 bool 值,如果为 true ,服务器提供者必有 provideswhen 两个方法,它们返回的是类组成的数组,provides 方法返回的类就是 deferred延时加载,when 方法返回的类就是 when 事件触发;否则当前服务器提供者就是 eager 即时加载。

    其次,写入 bootstrap/cache/services.php 缓存,方便下一次执行时,直接从这里面取分好的服务类;

    最后,调用容器 appregister 方法,将 eager 即时加载的类进行容器注册,赋值到容器类的 bindings 属性上;并把延时加载的类同样注册进容器中。

正文

public function bootstrap(Application $app)
{
    $app->registerConfiguredProviders();
}

上面这个就是 RegisterProviders 引导类的 bootstrap 方法,我们看到执行了容器的 registerConfiguredProviders 方法,我们进入这个方法

public function registerConfiguredProviders()
{
    $providers = Collection::make($this->config['app.providers'])
                    ->partition(function ($provider) {
                        return Str::startsWith($provider, 'Illuminate\\');
                    });

    $providers->splice(1, 0, [$this->make(PackageManifest::class)->providers()]);

    (new ProviderRepository($this, new Filesystem, $this->getCachedServicesPath()))
                ->load($providers->collapse()->toArray());
}

第一步:

$providers = Collection::make($this->config['app.providers'])
                    ->partition(function ($provider) {
                        return Str::startsWith($provider, 'Illuminate\\');
                    });

这段代码的作用是,根据 Illuminate 字符串切割为系统服务类和用户服务类。

通过 $this->config['app.providers']app.phpproviders 数组(放的是 Laravel 全部服务提供者)

然后,以全部服务提供者组成的数组为参数,调用集合类的 make 方法,之后再调用 partition 方法(此方法实现了切割功能)

我们重点看 partition 方法

public function partition($key, $operator = null, $value = null)
{
    $partitions = [new static, new static];

    $callback = func_num_args() === 1
            ? $this->valueRetriever($key)
            : $this->operatorForWhere(...func_get_args());

    foreach ($this->items as $key => $item) {
        $partitions[(int) ! $callback($item, $key)][$key] = $item;
    }

    return new static($partitions);
}

$partitions = [new static, new static]; 这行代码初始化切割存放的集合,数组第一个放的是系统服务提供者,第二个放的是用户服务提供者。

中间这些代码,就不用看了,它们就是实现具体切割,并返回切割好的集合。我们直接上图

file

file

file

第二步:

$providers->splice(1, 0, [$this->make(PackageManifest::class)->providers()]);

这个就是把 PackageManifest 类中的服务提供者也加入到集合中

file

这时候原先索引是 1 的用户服务提供者变成了 2,1 给了 PackageManifest 类中的服务提供者

第三步:(核心)

(new ProviderRepository($this, new Filesystem, $this->getCachedServicesPath()))
                ->load($providers->collapse()->toArray());

这段就是我开头是的先分类,再缓存,最后加载。

我们重点看 load 方法

public function load(array $providers)
{
    $manifest = $this->loadManifest();  // 这个就是加载缓存,如果没有就是 null

    if ($this->shouldRecompile($manifest, $providers)) {  // 如果是没有缓存,就进入 if 体,进行分类,写入缓存
        $manifest = $this->compileManifest($providers);
    }

    foreach ($manifest['when'] as $provider => $events) {  // 将 `when`事件加载类别的服务类进行注册
        $this->registerLoadEvents($provider, $events);
    }

    foreach ($manifest['eager'] as $provider) {  // 注册即时加载类别的服务类
        $this->app->register($provider);
    }

    $this->app->addDeferredServices($manifest['deferred']);  // 注册延时加载类别的服务类
}

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

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

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


AmberLavigne
`registerConfiguredProviders` 方法到底是哪个父类的?
0 个点赞 | 5 个回复 | 问答 | 课程版本 5.6