서비스 제공자
소개
서비스 제공자는 모든 라라벨 애플리케이션 부트스트래핑의 중심 장소입니다. 여러분의 애플리케이션 자체는 물론 라라벨의 모든 핵심 서비스도 서비스 제공자를 통해 부트스트랩됩니다.
하지만 "부트스트랩된다"는 것은 무엇을 의미할까요? 일반적으로 이는 서비스 컨테이너 바인딩, 이벤트 리스너, 미들웨어, 심지어 라우트까지 등록하는 것을 의미합니다. 서비스 제공자는 애플리케이션을 구성하는 중심 장소입니다.
라라벨은 메일러, 큐, 캐시 등과 같은 핵심 서비스를 부트스트랩하기 위해 내부적으로 수십 개의 서비스 제공자를 사용합니다. 이러한 제공자 중 다수는 "지연된" 제공자이며, 이는 모든 요청에 로드되지 않고 해당 제공자가 제공하는 서비스가 실제로 필요할 때만 로드된다는 의미입니다.
사용자가 정의한 모든 서비스 제공자는 bootstrap/providers.php 파일에 등록됩니다. 다음 문서에서는 자신만의 서비스 제공자를 작성하고 라라벨 애플리케이션에 등록하는 방법을 배울 수 있습니다.
라라벨이 요청을 처리하고 내부적으로 작동하는 방식에 대해 더 자세히 알고 싶다면 라라벨 요청 생명주기에 대한 문서를 확인하세요.
서비스 제공자 작성하기
모든 서비스 제공자는 Illuminate\Support\ServiceProvider 클래스를 확장합니다. 대부분의 서비스 제공자는 register 및 boot 메소드를 포함합니다. register 메소드 내에서는 서비스 컨테이너에만 바인딩해야 합니다. register 메소드 내에서 이벤트 리스너, 라우트 또는 기타 기능을 등록하려고 시도해서는 안 됩니다.
Artisan CLI는 make:provider 명령을 통해 새로운 제공자를 생성할 수 있습니다. 라라벨은 애플리케이션의 bootstrap/providers.php 파일에 새로운 제공자를 자동으로 등록합니다.
php artisan make:provider RiakServiceProvider
Register 메서드
이전에 언급했듯이, register 메서드 내에서는 서비스 컨테이너에만 바인딩해야 합니다. register 메서드 내에서 이벤트 리스너, 라우트 또는 기타 기능 조각을 등록하려고 시도해서는 안 됩니다. 그렇지 않으면 아직 로드되지 않은 서비스 제공자가 제공하는 서비스를 실수로 사용할 수 있습니다.
기본 서비스 제공자를 살펴보겠습니다. 서비스 제공자 메서드 내에서는 항상 서비스 컨테이너에 대한 액세스를 제공하는 $app 속성에 액세스할 수 있습니다.
<?php namespace App\Providers; use App\Services\Riak\Connection;use Illuminate\Contracts\Foundation\Application;use Illuminate\Support\ServiceProvider; class RiakServiceProvider extends ServiceProvider{ /** * 애플리케이션 서비스를 등록합니다. */ public function register(): void { $this->app->singleton(Connection::class, function (Application $app) { return new Connection(config('riak')); }); }}
이 서비스 제공자는 register 메서드만 정의하고 해당 메서드를 사용하여 서비스 컨테이너에서 App\Services\Riak\Connection의 구현을 정의합니다. Laravel의 서비스 컨테이너에 익숙하지 않다면 해당 문서를 확인하십시오.
bindings 및 singletons 속성
서비스 제공자가 많은 간단한 바인딩을 등록하는 경우 각 컨테이너 바인딩을 수동으로 등록하는 대신 bindings 및 singletons 속성을 사용할 수 있습니다. 프레임워크에서 서비스 제공자를 로드할 때 이러한 속성을 자동으로 확인하고 해당 바인딩을 등록합니다.
<?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{ /** * 등록해야 하는 모든 컨테이너 바인딩입니다. * * @var array */ public $bindings = [ ServerProvider::class => DigitalOceanServerProvider::class, ]; /** * 등록해야 하는 모든 컨테이너 싱글톤입니다. * * @var array */ public $singletons = [ DowntimeNotifier::class => PingdomDowntimeNotifier::class, ServerProvider::class => ServerToolsProvider::class, ];}
Boot 메서드
그렇다면 서비스 제공자 내에서 뷰 컴포저를 등록해야 하는 경우는 어떻게 될까요? 이것은 boot 메서드 내에서 수행해야 합니다. 이 메서드는 다른 모든 서비스 제공자가 등록된 후에 호출되므로 프레임워크에서 등록한 다른 모든 서비스에 액세스할 수 있습니다.
<?php namespace App\Providers; use Illuminate\Support\Facades\View;use Illuminate\Support\ServiceProvider; class ComposerServiceProvider extends ServiceProvider{ /** * 애플리케이션 서비스를 부트스트랩합니다. */ public function boot(): void { View::composer('view', function () { // ... }); }}
Boot 메서드 의존성 주입
서비스 제공자의 boot 메서드에 대한 의존성을 타입 힌트할 수 있습니다. 서비스 컨테이너는 필요한 모든 의존성을 자동으로 주입합니다.
use Illuminate\Contracts\Routing\ResponseFactory; /** * 애플리케이션 서비스를 부트스트랩합니다. */public function boot(ResponseFactory $response): void{ $response->macro('serialized', function (mixed $value) { // ... });}
제공자 등록
모든 서비스 제공자는 bootstrap/providers.php 구성 파일에 등록됩니다. 이 파일은 애플리케이션 서비스 제공자의 클래스 이름이 포함된 배열을 반환합니다.
<?php return [ App\Providers\AppServiceProvider::class,];
make:provider Artisan 명령을 호출하면 Laravel이 생성된 제공자를 bootstrap/providers.php 파일에 자동으로 추가합니다. 그러나 제공자 클래스를 수동으로 생성한 경우 제공자 클래스를 배열에 수동으로 추가해야 합니다.
<?php return [ App\Providers\AppServiceProvider::class, App\Providers\ComposerServiceProvider::class, ];
지연된 제공자
제공자가 서비스 컨테이너에서 바인딩만 등록하는 경우 등록된 바인딩 중 하나가 실제로 필요할 때까지 등록을 지연하도록 선택할 수 있습니다. 이러한 제공자의 로딩을 지연하면 모든 요청에서 파일 시스템에서 로드되지 않으므로 애플리케이션의 성능이 향상됩니다.
Laravel은 지연된 서비스 제공자가 제공하는 모든 서비스 목록과 서비스 제공자 클래스 이름을 컴파일하여 저장합니다. 그런 다음 이러한 서비스 중 하나를 확인하려고 할 때만 Laravel은 서비스 제공자를 로드합니다.
제공자 로딩을 지연하려면 \Illuminate\Contracts\Support\DeferrableProvider 인터페이스를 구현하고 provides 메서드를 정의합니다. provides 메서드는 제공자가 등록한 서비스 컨테이너 바인딩을 반환해야 합니다.
<?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{ /** * 애플리케이션 서비스를 등록합니다. */ public function register(): void { $this->app->singleton(Connection::class, function (Application $app) { return new Connection($app['config']['riak']); }); } /** * 제공자가 제공하는 서비스를 가져옵니다. * * @return array<int, string> */ public function provides(): array { return [Connection::class]; }}