内容简介:我们直接从下面是内核引导启动函数接着就是把这一组类传给
本章将通过分析加载流程深入理解系统内置和 app
中配置的 provider
是如何加载的
我们直接从 Kernel
的 handle()
方法中开始分析, handle()
负责处理了请求,所有框架的启动也是在这里开始!
protected function sendRequestThroughRouter($request) { $this->app->instance('request', $request); Facade::clearResolvedInstance('request'); $this->bootstrap(); // 这里就是内核的引导方法,故事也是从这里开始的。 return (new Pipeline($this->app)) ->send($request) ->through($this->app->shouldSkipMiddleware() ? [] : $this->middleware) ->then($this->dispatchToRouter()); } 复制代码
下面是内核引导启动函数
$this->bootstrappers() = [ \Illuminate\Foundation\Bootstrap\LoadEnvironmentVariables::class, \Illuminate\Foundation\Bootstrap\LoadConfiguration::class, \Illuminate\Foundation\Bootstrap\HandleExceptions::class, \Illuminate\Foundation\Bootstrap\RegisterFacades::class, \Illuminate\Foundation\Bootstrap\RegisterProviders::class, //找到了,它就是传给 App 对象进行启动的! \Illuminate\Foundation\Bootstrap\BootProviders::class, ] public function bootstrap() { if (! $this->app->hasBeenBootstrapped()) { $this->app->bootstrapWith($this->bootstrappers()); } } 复制代码
接着就是把这一组类传给 Application
对象的 bootstrapWith()
方法,继续下去
public function bootstrapWith(array $bootstrappers) { $this->hasBeenBootstrapped = true; foreach ($bootstrappers as $bootstrapper) { $this['events']->dispatch('bootstrapping: '.$bootstrapper, [$this]); // 启动中触发回调函数 $this->make($bootstrapper)->bootstrap($this); // 这里是我们要关注的功能。 $this['events']->dispatch('bootstrapped: '.$bootstrapper, [$this]); // 启动完成后触发回调函数 } } 复制代码
$this->make($bootstrapper)->bootstrap($this)
这个方法是从容器解析出传入的类,然后调用对应实例的 bootstrap($this)
方法
我们只追踪 \Illuminate\Foundation\Bootstrap\RegisterProviders::class
这个类,看看它的 bootstrap($this)
方法
public function bootstrap(Application $app) { $app->registerConfiguredProviders(); } 复制代码
继续看 Application
的 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()); } 复制代码
首先读取 $this->config['app.providers']
中的所有类名,以下是 laravel
框架默认的加载的服务提供者
'providers' => [ /* * Laravel Framework Service Providers... */ Illuminate\Auth\AuthServiceProvider::class, Illuminate\Broadcasting\BroadcastServiceProvider::class, Illuminate\Bus\BusServiceProvider::class, Illuminate\Cache\CacheServiceProvider::class, Illuminate\Foundation\Providers\ConsoleSupportServiceProvider::class, Illuminate\Cookie\CookieServiceProvider::class, Illuminate\Database\DatabaseServiceProvider::class, Illuminate\Encryption\EncryptionServiceProvider::class, Illuminate\Filesystem\FilesystemServiceProvider::class, Illuminate\Foundation\Providers\FoundationServiceProvider::class, Illuminate\Hashing\HashServiceProvider::class, Illuminate\Mail\MailServiceProvider::class, Illuminate\Notifications\NotificationServiceProvider::class, Illuminate\Pagination\PaginationServiceProvider::class, Illuminate\Pipeline\PipelineServiceProvider::class, Illuminate\Queue\QueueServiceProvider::class, Illuminate\Redis\RedisServiceProvider::class, Illuminate\Auth\Passwords\PasswordResetServiceProvider::class, Illuminate\Session\SessionServiceProvider::class, Illuminate\Translation\TranslationServiceProvider::class, Illuminate\Validation\ValidationServiceProvider::class, Illuminate\View\ViewServiceProvider::class, /* * Package Service Providers... */ /* * Application Service Providers... */ App\Providers\AppServiceProvider::class, App\Providers\AuthServiceProvider::class, // App\Providers\BroadcastServiceProvider::class, App\Providers\EventServiceProvider::class, App\Providers\RouteServiceProvider::class, ], 复制代码
通过集合来操作,按照命名空间来分区,这里目前只有两组 Illuminate
和 App
开头的类
继续分析 $providers->splice(1, 0, [$this->make(PackageManifest::class)->providers()]);
[$this->make(PackageManifest::class)->providers()]
这段代码是 Laravel 5.5
引入的包自动发现功能,
主要实现了从所有的包的 composer.json
文件下读取 laravel
下的 providers
中的内容。
在引入这个功能后很多包都不需要我们手动再去 app.providers
中去配置了。
在这行代码执行完成之后 $providers
会变成一个分成了三段的集合对象。
继续看下去 (new ProviderRepository($this, new Filesystem, $this->getCachedServicesPath())) ->load($providers->collapse()->toArray());
public function __construct(ApplicationContract $app, Filesystem $files, $manifestPath) { $this->app = $app; $this->files = $files; $this->manifestPath = $manifestPath; } 复制代码
这里首先实例化了一个 ProviderRepository
对象,这个对象需要三个参数 ( $app
, new Filesystem
, $this->getCachedServicesPath()
)
这里的 $this->getCachedServicesPath()
就是 bootstrap/cache/services.php
这个文件。
这里主要依靠 ProviderRepository
对象的 load()
来实现。
继续追踪 load()
方法
public function load(array $providers) { $manifest = $this->loadManifest(); if ($this->shouldRecompile($manifest, $providers)) { $manifest = $this->compileManifest($providers); } foreach ($manifest['when'] as $provider => $events) { $this->registerLoadEvents($provider, $events); } foreach ($manifest['eager'] as $provider) { $this->app->register($provider); } $this->app->addDeferredServices($manifest['deferred']); } 复制代码
展开 $manifest = $this->loadManifest();
public function loadManifest() { if ($this->files->exists($this->manifestPath)) { $manifest = $this->files->getRequire($this->manifestPath); if ($manifest) { return array_merge(['when' => []], $manifest); } } } 复制代码
可以看到如果存在刚才传入的 bootstrap/cache/services.php
这个文件则直接加载,之后合并参数返回。 为了直观,我们来看看 $manifest
的样子
继续看下一段,如果传入的 $providers
和缓存中取出来的结果不相同,则通过 $providers
重新构建缓存
if ($this->shouldRecompile($manifest, $providers)) { $manifest = $this->compileManifest($providers); } 复制代码
继续找下去,如果服务提供者的 when()
方法有返回事件则会在此处被监听
foreach ($manifest['when'] as $provider => $events) { $this->registerLoadEvents($provider, $events); } 复制代码
这里的类表示不需要延迟加载,因此框架会直接开始加载这些类
foreach ($manifest['eager'] as $provider) { $this->app->register($provider); } 复制代码
$this->app->addDeferredServices($manifest['deferred']);
最后一段就是延迟加载的功能了!
public function addDeferredServices(array $services) { $this->deferredServices = array_merge($this->deferredServices, $services); } 复制代码
这段代码就是将当前 $services
中的值合并到 $app
对象的 $deferredServices
成员中。
额外拓展,关于延迟加载的实现
这是 $app 对象的make方法,通过判断是否存在延迟加载的成员,如存在且没有在$instances中共享 的对象就会被加载,laravel 本身就是功能非常庞大的框架,因此延迟加载也是对性能提升的一种手段! public function make($abstract, array $parameters = []) { $abstract = $this->getAlias($abstract); if (isset($this->deferredServices[$abstract]) && ! isset($this->instances[$abstract])) { $this->loadDeferredProvider($abstract); } return parent::make($abstract, $parameters); } 复制代码
分析到这里基本上 Laravel
的服务提供者功能是如何运作的就分解完了,其中关于 Filesystem
和 ProviderRepository
对象的功能没有详细分解,这里东西并不多,不展开了!
还有就是 PackageManifest::class
这个对象的功能主要是从 composer.json
的交互以及构建 bootstrap/cache
下面的缓存文件。
可以梳理一下思路:
框架是怎么加载的 (优先缓存文件,对比更新)
provider 提供了那些功能(延迟加载,事件监听)...
包自动发现的实现! (通过读取composer.json)
延迟加载的实现逻辑
以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网
猜你喜欢:- 【Laravel-海贼王系列】第十四章,Session 解析
- 【Laravel-海贼王系列】第十二章,Facade 模式解析
- 【Laravel-海贼王系列】第十章,Job&队列存储端实现
- 【Laravel-海贼王系列】第十三章,路由&控制器解析
- 【Laravel-海贼王系列】第十七章,Laravel 那些骚操作
- 慢雾安全 海贼王:从DApp亡灵军团,细说区块链安全
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
设计模式之禅(第2版)
秦小波 / 机械工业出版社 / 2014-2-25 / 89.00元
本书是设计模式领域公认的3本经典著作之一,“极具趣味,容易理解,但讲解又极为严谨和透彻”是本书的写作风格和方法的最大特点。第1版2010年出版,畅销至今,广受好评,是该领域的里程碑著作。深刻解读6大设计原则和28种设计模式的准确定义、应用方法和最佳实践,全方位比较各种同类模式之间的异同,详细讲解将不同的模式组合使用的方法。第2版在第1版的基础上有两方面的改进,一方面结合读者的意见和建议对原有内容中......一起来看看 《设计模式之禅(第2版)》 这本书的介绍吧!