注册服务
简介
这一章,我们来看一下引导程序中的注册服务。
-
先了解一下这个注册服务干了什么:
首先,对
app.php
配置文件中providers
数组内的服务器提供者进行分类,分为主要的三类:deferred
延时加载、eager
即时加载、when
事件触发。分类依据是看这个服务器提供者中
$defer
属性的bool
值,如果为true
,服务器提供者必有provides
和when
两个方法,它们返回的是类组成的数组,provides
方法返回的类就是deferred
延时加载,when
方法返回的类就是when
事件触发;否则当前服务器提供者就是eager
即时加载。其次,写入
bootstrap/cache/services.php
缓存,方便下一次执行时,直接从这里面取分好的服务类;最后,调用容器
app
的register
方法,将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.php
中 providers
数组(放的是 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];
这行代码初始化切割存放的集合,数组第一个放的是系统服务提供者,第二个放的是用户服务提供者。
中间这些代码,就不用看了,它们就是实现具体切割,并返回切割好的集合。我们直接上图
第二步:
$providers->splice(1, 0, [$this->make(PackageManifest::class)->providers()]);
这个就是把 PackageManifest
类中的服务提供者也加入到集合中
这时候原先索引是 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']); // 注册延时加载类别的服务类
}
本篇如有错误、不当或者需补充的内容,请各位同僚多提宝贵意见。