概述
在上一章我們了解,服務容器實現(xiàn)了 IOC
控制反轉(zhuǎn)讼庇。為了實現(xiàn)這種控制反轉(zhuǎn)灸拍,就需要綁定對象生成器的工作做祝,在Laravel 中,服務提供者來實現(xiàn)這項工作的鸡岗。 服務提供者 是 Laravel
應用啟動的中心混槐,你自己的應用以及所有 Laravel 的核心服務都是通過服務提供者啟動。 當然啟動這些服務纤房,需要加載注冊服務纵隔,包括注冊服務容器綁定翻诉、事件監(jiān)聽器炮姨、中間件甚至路由。服務提供者是應用配置的中心碰煌。
編寫服務提供者
所有的服務提供者都繼承自 Illuminate\Support\ServiceProvider
類舒岸。大部分服務提供者都包含兩個方法: register
和 boot
。
通過 Artisan 命令 make:provider
即可生成一個新的提供者:
php artisan make:provider RiakServiceProvider
register方法
在 register
方法中只綁定事物到 服務容器芦圾,而不要做其他事情蛾派。
<?php
namespace App\Providers;
use Riak\Connection;
use Illuminate\Support\ServiceProvider;
class RiakServiceProvider extends ServiceProvider{
/**
* 在容器中注冊綁定.
*
* @return void
*/
public function register()
{
$this->app->singleton(Connection::class, function ($app) {
return new Connection(config('riak'));
});
}
}
該服務提供者只定義了一個 register
方法,并使用該方法在服務容器中定義了一個 Riak\Contracts\Connection
的實現(xiàn)个少。如果你不知道服務容器是如何工作的洪乍,請參考服務容器。
boot方法
如果我們想要在服務提供者中注冊視圖 composer 該怎么做夜焦?這就要用到 boot 方法了壳澳。該方法在所有服務提供者被注冊以后才會被調(diào)用,這就是說我們可以在其中訪問框架已注冊的所有其它服務:
<?php
namespace App\Providers;
use Illuminate\Support\ServiceProvider;
class ComposerServiceProvider extends ServiceProvider{
/**
* Perform post-registration booting of services.
*
* @return void
*/
public function boot()
{
view()->composer('view', function () {
//
});
}
}
boot
方法在 register
方法之后調(diào)用茫经,這就意味著巷波,你無須擔心在注入某個實例的時候萎津,他還沒有被綁定或?qū)嵗?/p>
例如你建立了
SegmentFault
和SegmentFaultApi
兩個類,前者依賴與后者抹镊,但是在register
中你不確定那個類先被實例化了锉屈,那么你可以在boot
中再對后者進行引用,因為此時兩個類都已經(jīng)進行正確的配置垮耳。
boot方法的 依賴注入
我們可以在 boot
方法中類型提示依賴颈渊,服務容器會自動注冊你所需要的依賴:
use Illuminate\Contracts\Routing\ResponseFactory;
public function boot(ResponseFactory $response){
$response->macro('caps', function ($value) {
//
});
}
注冊服務提供者
所有服務提供者都是通過配置文件 config/app.php
中進行注冊,該文件包含了一個列出所有服務提供者名字的 providers
數(shù)組终佛,默認情況下儡炼,其中列出了所有核心服務提供者,這些服務提供者啟動 Laravel核心組件查蓉,比如郵件乌询、隊列、緩存等等豌研。
你可以在該數(shù)組中進行添加注冊提供者:
'providers' => [
/*
* Laravel 框架系統(tǒng)服務...
*/
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...
*/
//
/*
*應用程序服務...
*/
App\Providers\AppServiceProvider::class,
App\Providers\AuthServiceProvider::class,
// App\Providers\BroadcastServiceProvider::class,
App\Providers\EventServiceProvider::class,
App\Providers\RouteServiceProvider::class,
],
延遲加載服務提供者
如果你的提供者僅僅只是在服務容器中注冊綁定妹田,你可以選擇延遲加載該綁定直到注冊綁定的服務真的需要時再加載,延遲加載這樣的一個提供者將會提升應用的性能鹃共,因為它不會在每次請求時都從文件系統(tǒng)加載鬼佣。
Laravel 編譯并保存所有延遲服務提供者提供的服務及服務提供者的類名。然后霜浴,只有當你嘗試解析其中某個服務時 Laravel
才會加載其服務提供者晶衷。
想要延遲加載一個提供者,設置 defer
屬性為 true
并定義一個 provides
方法阴孟,該方法返回該提供者注冊的服務容器綁定:
<?php
namespace App\Providers;
use Riak\Connection;
use Illuminate\Support\ServiceProvider;
class RiakServiceProvider extends ServiceProvider{
/**
* 服務提供者加是否延遲加載.
*
* @var bool
*/
protected $defer = true;
/**
* 注冊服務提供者
*
* @return void
*/
public function register()
{
$this->app->singleton(Connection::class, function ($app) {
return new Connection($app['config']['riak']);
});
}
/**
* 獲取由提供者提供的服務.
*
* @return array
*/
public function provides()
{
return [Connection::class];
}
}
laravel 會編譯和存儲所有延遲加載的服務提供者的服務列表及服務提供者的類名晌纫。然后,只有當你嘗試解析其中的某個服務時永丝,laravel 才會加載其服務提供者锹漱。