Open xiaohuilam opened 5 years ago
前面 《02. Kernel Handle解析》 结尾,我们留下了 注册服务提供者 和 启动服务提供者 是两个比较重要的步骤的悬念,接下来两篇文章,我们来分别解析这两大流程。
注册服务提供者
启动服务提供者
https://github.com/xiaohuilam/laravel/blob/d081c918b7e582ec5b3f94316f44834466cec37d/vendor/laravel/framework/src/Illuminate/Foundation/Bootstrap/RegisterProviders.php#L1-L19
整个 RegisterProviders 都是粮衣,其没有任何功能功能代码,而是调用到了 Illuminate\Foundation\ Application 的 registerConfiguredProviders
Illuminate\Foundation\ Application
registerConfiguredProviders
注意运行时实际并没有调用 Illuminate\Contracts\Foundation\Application 的 registerConfiguredProviders,而是调用了其具体实现类 Illuminate\Foundation\ Application 的 registerConfiguredProviders。不要被上面代码中的注解表象所迷惑
https://github.com/xiaohuilam/laravel/blob/d081c918b7e582ec5b3f94316f44834466cec37d/vendor/laravel/framework/src/Illuminate/Foundation/Application.php#L533-L549
上面第 540-543 行是将 config/app.php 中配置的 providers https://github.com/xiaohuilam/laravel/blob/d081c918b7e582ec5b3f94316f44834466cec37d/config/app.php#L122-L163 读取出来,判断是否为 Illuminate\ 开头,归为两组:
config/app.php
providers
Illuminate\
Illuminate\Support\Collection {#2825 all: [ Illuminate\Support\Collection {#2822 all: [ "Illuminate\Auth\AuthServiceProvider", "Illuminate\Broadcasting\BroadcastServiceProvider", "Illuminate\Bus\BusServiceProvider", "Illuminate\Cache\CacheServiceProvider", "Illuminate\Foundation\Providers\ConsoleSupportServiceProvider", "Illuminate\Cookie\CookieServiceProvider", "Illuminate\Database\DatabaseServiceProvider", "Illuminate\Encryption\EncryptionServiceProvider", "Illuminate\Filesystem\FilesystemServiceProvider", "Illuminate\Foundation\Providers\FoundationServiceProvider", "Illuminate\Hashing\HashServiceProvider", "Illuminate\Mail\MailServiceProvider", "Illuminate\Notifications\NotificationServiceProvider", "Illuminate\Pagination\PaginationServiceProvider", "Illuminate\Pipeline\PipelineServiceProvider", "Illuminate\Queue\QueueServiceProvider", "Illuminate\Redis\RedisServiceProvider", "Illuminate\Auth\Passwords\PasswordResetServiceProvider", "Illuminate\Session\SessionServiceProvider", "Illuminate\Translation\TranslationServiceProvider", "Illuminate\Validation\ValidationServiceProvider", "Illuminate\View\ViewServiceProvider", ], }, Illuminate\Support\Collection {#2823 all: [ "22" => "App\Providers\AppServiceProvider", "22" => "App\Providers\AuthServiceProvider", "22" => "App\Providers\EventServiceProvider", "22" => "App\Providers\RouteServiceProvider", ], }, ], }
接着 $providers->splice(1, 0, [$this->make(PackageManifest::class)->providers()]) 这一行会得到如下结果
$providers->splice(1, 0, [$this->make(PackageManifest::class)->providers()])
Illuminate\Support\Collection {#33 #items: array:3 [ 0 => Illuminate\Support\Collection {#21 #items: array:22 [ 0 => "Illuminate\Auth\AuthServiceProvider" 1 => "Illuminate\Broadcasting\BroadcastServiceProvider" 2 => "Illuminate\Bus\BusServiceProvider" 3 => "Illuminate\Cache\CacheServiceProvider" 4 => "Illuminate\Foundation\Providers\ConsoleSupportServiceProvider" 5 => "Illuminate\Cookie\CookieServiceProvider" 6 => "Illuminate\Database\DatabaseServiceProvider" 7 => "Illuminate\Encryption\EncryptionServiceProvider" 8 => "Illuminate\Filesystem\FilesystemServiceProvider" 9 => "Illuminate\Foundation\Providers\FoundationServiceProvider" 10 => "Illuminate\Hashing\HashServiceProvider" 11 => "Illuminate\Mail\MailServiceProvider" 12 => "Illuminate\Notifications\NotificationServiceProvider" 13 => "Illuminate\Pagination\PaginationServiceProvider" 14 => "Illuminate\Pipeline\PipelineServiceProvider" 15 => "Illuminate\Queue\QueueServiceProvider" 16 => "Illuminate\Redis\RedisServiceProvider" 17 => "Illuminate\Auth\Passwords\PasswordResetServiceProvider" 18 => "Illuminate\Session\SessionServiceProvider" 19 => "Illuminate\Translation\TranslationServiceProvider" 20 => "Illuminate\Validation\ValidationServiceProvider" 21 => "Illuminate\View\ViewServiceProvider" ] } 1 => array:5 [ 0 => "BeyondCode\DumpServer\DumpServerServiceProvider" 1 => "Fideloper\Proxy\TrustedProxyServiceProvider" 2 => "Laravel\Tinker\TinkerServiceProvider" 3 => "Carbon\Laravel\ServiceProvider" 4 => "NunoMaduro\Collision\Adapters\Laravel\CollisionServiceProvider" ] 2 => Illuminate\Support\Collection {#31 #items: array:4 [ 22 => "App\Providers\AppServiceProvider" 23 => "App\Providers\AuthServiceProvider" 24 => "App\Providers\EventServiceProvider" 25 => "App\Providers\RouteServiceProvider" ] } ] }
最后一句代码
(new ProviderRepository($this, new Filesystem, $this->getCachedServicesPath())) ->load($providers->collapse()->toArray());
第一步是将加载缓存好的 bootstrap/cache/services.php https://github.com/xiaohuilam/laravel/blob/d081c918b7e582ec5b3f94316f44834466cec37d/vendor/laravel/framework/src/Illuminate/Foundation/Application.php#L855-L863
bootstrap/cache/services.php
其实就是执行 ProviderRepository::load() $providers-> collapse() 得到的数组 (这个数组是前面 splice 拆分后再并入的)。 https://github.com/xiaohuilam/laravel/blob/d081c918b7e582ec5b3f94316f44834466cec37d/vendor/laravel/framework/src/Illuminate/Foundation/ProviderRepository.php#L47-L79
ProviderRepository::load()
splice
这句 loadManifest 即为加载前面传入的 bootstrap/cache/services.php https://github.com/xiaohuilam/laravel/blob/d081c918b7e582ec5b3f94316f44834466cec37d/vendor/laravel/framework/src/Illuminate/Foundation/ProviderRepository.php#L81-L98
第60行调用到的的 shouldRecompile 逻辑为判断是否 provider 不符合,代码 https://github.com/xiaohuilam/laravel/blob/d081c918b7e582ec5b3f94316f44834466cec37d/vendor/laravel/framework/src/Illuminate/Foundation/ProviderRepository.php#L100-L110
shouldRecompile
provider
如果需要重新编译此服务提供者缓存的 bootstrap/cache/services.php ,把数据 $manifest 提取到 bootstrap/cache/services.php ,具体过程为: https://github.com/xiaohuilam/laravel/blob/d081c918b7e582ec5b3f94316f44834466cec37d/vendor/laravel/framework/src/Illuminate/Foundation/ProviderRepository.php#L130-L166 https://github.com/xiaohuilam/laravel/blob/d081c918b7e582ec5b3f94316f44834466cec37d/vendor/laravel/framework/src/Illuminate/Foundation/ProviderRepository.php#L179-L198
$manifest
到这时,ProviderRepository::load() 的服务提供者缓存的判断和执行流程就结束了。我们回到 ProviderRepository::load() 的后面流程,接下来就是 https://github.com/xiaohuilam/laravel/blob/d081c918b7e582ec5b3f94316f44834466cec37d/vendor/laravel/framework/src/Illuminate/Foundation/ProviderRepository.php#L64-L69
没错,触发 registerLoadEvents 方法了。感谢 laravel 代码做到了足够语义化,我们猜到了这里就是触发服务提供者注册事件的。具体流程为: https://github.com/xiaohuilam/laravel/blob/d081c918b7e582ec5b3f94316f44834466cec37d/vendor/laravel/framework/src/Illuminate/Foundation/ProviderRepository.php#L112-L128
registerLoadEvents
再继续后面,就是 ProviderRepository::load() 触发容器的 register 的流程了 https://github.com/xiaohuilam/laravel/blob/d081c918b7e582ec5b3f94316f44834466cec37d/vendor/laravel/framework/src/Illuminate/Foundation/ProviderRepository.php#L71-L76
register
Illuminate\Foundation\Container\Appplication 容器的 register 方法代码为 https://github.com/xiaohuilam/laravel/blob/d081c918b7e582ec5b3f94316f44834466cec37d/vendor/laravel/framework/src/Illuminate/Foundation/Application.php#L551-L600
Illuminate\Foundation\Container\Appplication
步骤
getProvider
$force
$provier
$provider
$bindings
$key
$value
Illuminate\Foundation\Container\Appplication::bind($key, $value)
$singletons
Illuminate\Foundation\Container\Appplication::singleton($key, $value)
Illuminate\Foundation\Container\Appplication::$loadedProviders[ServiceProvider::class] = true
bootProvider($provider)
ServiceProvider Register 解析
代码
https://github.com/xiaohuilam/laravel/blob/d081c918b7e582ec5b3f94316f44834466cec37d/vendor/laravel/framework/src/Illuminate/Foundation/Bootstrap/RegisterProviders.php#L1-L19
解析
整个 RegisterProviders 都是粮衣,其没有任何功能功能代码,而是调用到了
Illuminate\Foundation\ Application
的registerConfiguredProviders
https://github.com/xiaohuilam/laravel/blob/d081c918b7e582ec5b3f94316f44834466cec37d/vendor/laravel/framework/src/Illuminate/Foundation/Application.php#L533-L549
上面第 540-543 行是将
config/app.php
中配置的providers
https://github.com/xiaohuilam/laravel/blob/d081c918b7e582ec5b3f94316f44834466cec37d/config/app.php#L122-L163 读取出来,判断是否为Illuminate\
开头,归为两组:接着
$providers->splice(1, 0, [$this->make(PackageManifest::class)->providers()])
这一行会得到如下结果最后一句代码
第一步是将加载缓存好的
bootstrap/cache/services.php
https://github.com/xiaohuilam/laravel/blob/d081c918b7e582ec5b3f94316f44834466cec37d/vendor/laravel/framework/src/Illuminate/Foundation/Application.php#L855-L863其实就是执行
ProviderRepository::load()
$providers-> collapse() 得到的数组 (这个数组是前面splice
拆分后再并入的)。 https://github.com/xiaohuilam/laravel/blob/d081c918b7e582ec5b3f94316f44834466cec37d/vendor/laravel/framework/src/Illuminate/Foundation/ProviderRepository.php#L47-L79这句 loadManifest 即为加载前面传入的
bootstrap/cache/services.php
https://github.com/xiaohuilam/laravel/blob/d081c918b7e582ec5b3f94316f44834466cec37d/vendor/laravel/framework/src/Illuminate/Foundation/ProviderRepository.php#L81-L98第60行调用到的的
shouldRecompile
逻辑为判断是否provider
不符合,代码 https://github.com/xiaohuilam/laravel/blob/d081c918b7e582ec5b3f94316f44834466cec37d/vendor/laravel/framework/src/Illuminate/Foundation/ProviderRepository.php#L100-L110如果需要重新编译此服务提供者缓存的
bootstrap/cache/services.php
,把数据$manifest
提取到bootstrap/cache/services.php
,具体过程为: https://github.com/xiaohuilam/laravel/blob/d081c918b7e582ec5b3f94316f44834466cec37d/vendor/laravel/framework/src/Illuminate/Foundation/ProviderRepository.php#L130-L166 https://github.com/xiaohuilam/laravel/blob/d081c918b7e582ec5b3f94316f44834466cec37d/vendor/laravel/framework/src/Illuminate/Foundation/ProviderRepository.php#L179-L198到这时,ProviderRepository::load() 的服务提供者缓存的判断和执行流程就结束了。我们回到 ProviderRepository::load() 的后面流程,接下来就是 https://github.com/xiaohuilam/laravel/blob/d081c918b7e582ec5b3f94316f44834466cec37d/vendor/laravel/framework/src/Illuminate/Foundation/ProviderRepository.php#L64-L69
没错,触发
registerLoadEvents
方法了。感谢 laravel 代码做到了足够语义化,我们猜到了这里就是触发服务提供者注册事件的。具体流程为: https://github.com/xiaohuilam/laravel/blob/d081c918b7e582ec5b3f94316f44834466cec37d/vendor/laravel/framework/src/Illuminate/Foundation/ProviderRepository.php#L112-L128再继续后面,就是 ProviderRepository::load() 触发容器的
register
的流程了 https://github.com/xiaohuilam/laravel/blob/d081c918b7e582ec5b3f94316f44834466cec37d/vendor/laravel/framework/src/Illuminate/Foundation/ProviderRepository.php#L71-L76Illuminate\Foundation\Container\Appplication
容器的register
方法代码为 https://github.com/xiaohuilam/laravel/blob/d081c918b7e582ec5b3f94316f44834466cec37d/vendor/laravel/framework/src/Illuminate/Foundation/Application.php#L551-L600步骤
getProvider
这个服务,如果能取到证明注册过了,除非要求强硬方式$force
就不再注册$provier
为具体的 ServiceProvider 对象$provider
有无register
方法,有则运行$provider
有无定义$bindings
属性,若有,则依次$key
,$value
为参,进入Illuminate\Foundation\Container\Appplication::bind($key, $value)
执行$provider
有无定义$singletons
属性,若有,则依次$key
,$value
为参,进入Illuminate\Foundation\Container\Appplication::singleton($key, $value)
执行Illuminate\Foundation\Container\Appplication::$loadedProviders[ServiceProvider::class] = true
bootProvider($provider)