Các service provider là trung tâm của tất cả quá trình khởi động của application Laravel. Application của bạn, cũng như tất cả các service core của Laravel, đều được khởi động thông qua các service provider.
Nhưng, "bootstrapped" nghĩa là gì? Nói chung, ý của chúng tôi có nghĩa là đăng ký những thứ, bao gồm cả đăng ký liên kết service container, event listener, middleware và thậm chí là cả các route. Các Service provider là trung tâm để cấu hình application của bạn.
Laravel sử dụng nhiều service provider nội bộ để khởi động các service cốt lõi của nó, chẳng hạn như mailer, queue, cache và các thành phần khác. Nhiều trong số này là các provider "hoãn", nghĩa là nó sẽ không được load trong mọi request, mà chỉ khi các service này thực sự cần thiết nó mới được load.
Tất cả các service provider do người dùng định nghĩa đều được đăng ký trong file bootstrap/providers.php. Trong tài liệu này, bạn sẽ học cách viết các service provider của riêng bạn và đăng ký chúng với application Laravel.
[!NOTE] Nếu bạn muốn tìm hiểu thêm về cách Laravel xử lý các request và hoạt động nội bộ trong Laravel, hãy xem tài liệu của chúng tôi về Laravel vòng đời request.
Tất cả các service provider đều được extend từ class Illuminate\Support\ServiceProvider. Hầu hết các service provider đều chứa một phương thức register và một phương thức boot. Trong phương thức register, bạn chỉ nên liên kết vào service container. Bạn đừng bao giờ đăng ký bất kỳ event listener, routes hoặc bất kỳ phần chức năng nào khác vào trong phương thức register.
Artisan CLI có thể tạo một provider mới thông qua lệnh make:provider. Laravel sẽ tự động đăng ký provider mới của bạn vào file bootstrap/providers.php của application của bạn:
php artisan make:provider RiakServiceProvider
Như đã đề cập trước, trong phương thức register, bạn chỉ nên liên kết vào service container. Bạn đừng bao giờ đăng ký bất kỳ event listener, routes hoặc bất kỳ phần chức năng nào khác vào trong phương thức register. Vì, bạn có thể vô tình sử dụng một service được cung cấp bởi một service provider khác mà chưa được load.
Chúng ta hãy cùng xem một service provider cơ bản. Trong bất kỳ phương thức nào của service provider, bạn luôn có quyền truy cập vào thuộc tính $app, mà cung cấp quyền truy cập vào service container:
<?php
namespace App\Providers;
use App\Services\Riak\Connection;
use Illuminate\Contracts\Foundation\Application;
use Illuminate\Support\ServiceProvider;
class RiakServiceProvider extends ServiceProvider
{
/**
* Register any application services.
*/
public function register(): void
{
$this->app->singleton(Connection::class, function (Application $app) {
return new Connection(config('riak'));
});
}
}
Service provider này chỉ định nghĩa một phương thức register và sử dụng phương thức đó để định nghĩa một implementation của App\Services\Riak\Connection trong service container. Nếu bạn chưa quen với service container của Laravel, hãy xem tài liệu về nó.
bindings và singletonsNếu service provider của bạn đăng ký nhiều liên kết, thì bạn có thể muốn sử dụng thuộc tính bindings và singletons để đăng ký thay vì đăng ký thủ công từng liên kết một vào container. Khi service provider được load bởi framework, nó sẽ tự động kiểm tra các thuộc tính này và đăng ký các liên kết mà bạn đã khai báo:
<?php
namespace App\Providers;
use App\Contracts\DowntimeNotifier;
use App\Contracts\ServerProvider;
use App\Services\DigitalOceanServerProvider;
use App\Services\PingdomDowntimeNotifier;
use App\Services\ServerToolsProvider;
use Illuminate\Support\ServiceProvider;
class AppServiceProvider extends ServiceProvider
{
/**
* All of the container bindings that should be registered.
*
* @var array
*/
public $bindings = [
ServerProvider::class => DigitalOceanServerProvider::class,
];
/**
* All of the container singletons that should be registered.
*
* @var array
*/
public $singletons = [
DowntimeNotifier::class => PingdomDowntimeNotifier::class,
ServerProvider::class => ServerToolsProvider::class,
];
}
Vậy, điều gì sẽ xảy ra nếu chúng ta cần đăng ký một view composer trong service provider của chúng ta? Điều này nên được thực hiện trong phương thức boot. Phương thức này được gọi sau khi tất cả các service provider khác đã được đăng ký, nghĩa là bạn có quyền truy cập vào tất cả các service khác đã được đăng ký theo framework:
<?php
namespace App\Providers;
use Illuminate\Support\Facades\View;
use Illuminate\Support\ServiceProvider;
class ComposerServiceProvider extends ServiceProvider
{
/**
* Bootstrap any application services.
*/
public function boot(): void
{
View::composer('view', function () {
// ...
});
}
}
Bạn có thể viết khai báo phụ thuộc vào trong phương thức boot của service provider của bạn. service container sẽ tự động tích hợp bất kỳ phụ thuộc nào mà bạn cần:
use Illuminate\Contracts\Routing\ResponseFactory;
/**
* Bootstrap any application services.
*/
public function boot(ResponseFactory $response): void
{
$response->macro('serialized', function (mixed $value) {
// ...
});
}
Tất cả các service provider được đăng ký trong file cấu hình bootstrap/providers.php. File này trả về một mảng chứa các tên class của các service provider của application của bạn:
<?php
return [
App\Providers\AppServiceProvider::class,
];
Khi bạn gọi lệnh Artisan make:provider, Laravel sẽ tự động thêm provider được tạo vào file bootstrap/providers.php. Tuy nhiên, nếu bạn đã tạo class provider rồi, thì bạn nên tự thêm class provider vào mảng:
<?php
return [
App\Providers\AppServiceProvider::class,
App\Providers\ComposerServiceProvider::class, // [tl! add]
];
Nếu provider của bạn chỉ đăng ký các liên kết trong service container, bạn có thể chọn trì hoãn việc đăng ký cho đến khi một trong số các đăng ký liên kết thật sự cần thiết. Việc trì hoãn load của một provider như vậy sẽ cải thiện hiệu suất của ứng dụng của bạn, vì nó không được load từ filesystem cho mỗi request.
Laravel sẽ biên dịch và lưu trữ một danh sách tất cả các service mà được cung cấp dưới các service provider trì hoãn, cùng với tên của class service provider đó. Sau đó, chỉ khi bạn resolve một trong những service này thì Laravel mới tải service provider đó lên.
Để trì hoãn việc load của một provider, hãy implement interface \Illuminate\Contracts\Support\DeferrableProvider và định nghĩa một phương thức provides. Phương thức provides sẽ trả về các liên kết service container được đăng ký bởi provider:
<?php
namespace App\Providers;
use App\Services\Riak\Connection;
use Illuminate\Contracts\Foundation\Application;
use Illuminate\Contracts\Support\DeferrableProvider;
use Illuminate\Support\ServiceProvider;
class RiakServiceProvider extends ServiceProvider implements DeferrableProvider
{
/**
* Register any application services.
*/
public function register(): void
{
$this->app->singleton(Connection::class, function (Application $app) {
return new Connection($app['config']['riak']);
});
}
/**
* Get the services provided by the provider.
*
* @return array<int, string>
*/
public function provides(): array
{
return [Connection::class];
}
}
entry