서비스 프로바이더(Service Provider)

서비스 프로바이더는 라라벨 애플리케이션의 부트스트래핑(bootstrapping )의 핵심으로 라라벨 프레임워크의 주요 기능은 서비스 프로바이더를 통해서 제공됩니다.

이 책의 독자들은 서비스 프로바이더를 라라벨 프레임워크의 패키지 또는 익스텐션을 부팅해주는 매커니즘 정도로 이해하면 됩니다.

 

라라벨에 등록된 전체 서비스 프로바이더의 목록은 config/app.php 의 providers 항목을 통해 확인할 수 있으며 만약 사용하는 라이브러리가 있고 이를 라라벨 프레임워크와 통합하고 싶은 개발자는 라라벨의 Illuminate\Support\ServiceProvider 클래스를 상속받아서 나만의 서비스 프로바이더를 개발하면 됩니다.

 

외부에서 개발한 라라벨 패키지를 내 애플리케이션에 추가하여 사용할 경우 컴포저를 통해 패키지를 설치하고 프로바이더 항목에 등록해 주면 됩니다.

다음은 유명한 PHP 이미지 처리 라이브러리인 "Intervention Image" 를 라라벨 프로바이더로 등록하는 방법입니다.

config/app.php

 'providers' => [
        /*
         * Laravel Framework Service Providers...
         */
        Illuminate\Foundation\Providers\ArtisanServiceProvider::class,
		Illuminate\Auth\AuthServiceProvider::class,
		Illuminate\Broadcasting\BroadcastServiceProvider::class,
		Illuminate\Bus\BusServiceProvider::class,
		/* ... */
 
		/* Intervention Image 서비스 프로바이더 등록*/
		Intervention\Image\ImageServiceProvider::class,
PHP

 

서비스 프로바이더의 개념 및 용도, 외부 프로바이더를 등록하는 방법을 알아야 방대하고 강력한 라라벨 패키지를 원활하게 사용할 수 있으며 적절한 외부 패키지 사용은 NIH(Not invented here) 신드롬을 방지하고  프로젝트 자체에 집중할 수 있는 좋은 방법입니다.

 

직접 라라벨 패키지를 만들 경우 서비스 프로바이더를 직접 작성해야 하므로 이보다 더 깊은 이해가 필요하며 관심있는 독자들은 서비스 프로바이더 작성하기(http://goo.gl/juFs5c) 문서를 참고하기 바랍니다.

 

파사드(Facade)

파사드는 디자인 패턴(design Pattern)중 하나로 복잡한 아키텍처를 숨기고 간략한 API 로 접근하기 위해 추상화하는 기법이지만 라라벨의 파사드는 다른 프레임워크의 파사드보다는 서비스 컨테이너에 대한 프락시 패턴(Proxy Pattern) 에 더 가깝습니다.

 

주요 적용 예를 들어 보면 라라벨은 캐시(Cache) 를 파일 시스템, 데이타베이스, 멤캐쉬드, 레디스(Redis) 등 다양한 저장소에 저장하고 가져올 수 있습니다.

저장소에 캐시를 유효 기간을 30분으로 하여 저장할 경우 app 코드는 아래와 같습니다.

Cache::put('key', 'cache value', 30);
CODE

실제로는 캐시 저장소 종류마다 연계하는 프로토콜과 내부 구조가 다르므로 실제 저장소와  연결하여 캐시를 처리하는 아답터 내부에서는 다음과 같은 작업이 이루어 집니다.

  • 파일시스템 저장소
    1. 캐시 유효 기간을 초로 환산하고 이 값 뒤에 value 를 추가
    2. 입력한 key 이름으로 캐시 파일을 생성(기존에 있을 경우 덮어씀)하고 1번에서 생성한 값을 파일 내용에 저장.
  • 데이타베이스 저장소
    1. 캐시 value 를 .env 에  설정한 키 값으로 암호화
    2. 테이블에 key와, 암호화한 캐시 value, 캐시 유효 기간을 삽입
    3. Key 가 이미 있어서 예외가 발생할 경우 테이블에 기존 데이타 업데이트
  • 레디스저장소
    1. setex 명령으로 입력한 key 와 캐시 유효기간, value 를 레디스에 저장

라라벨은 파사드를 통해 프레임워크의 구성 요소를 추상화하여 제공하고 있습니다. 라라벨이 제공하고 있는 파사드 목록을 보려면 config/app.php 의 항목중 aliases 항목을 보면 됩니다.

 

추가로 라라벨 파사드는 서비스 프로바이더에 대한 정적 프록시(Static Proxies) 를 제공합니다. 이 말은 서비스 프로바이더를 사용할 경우 new 로 객체를 생성하지 않고 다음과 같이 정적 메소드를 호출하는 문법으로 사용할 수 있다는 의미입니다.

$user = Cache::get('user:' . $id);
CODE

 

문법은 정적이지만 위 Cache::get 메소드는 정적이 아니며 라라벨은 cache 에 바인딩된 객체를 찾아서 의존성을 주입한 후(REF: 의존성 주입) 이 객체(FileStore, DatabaseStore 등)의 get 메소드를 호출하게 됩니다. 

$user = $this->app->make('cache')->get('user:' . $id);
CODE

라라벨은 이로써 new 를 사용하지 않고도 편리하게 객체의 메소드를 호출할 수 있으며 런타임에 개체를 동적으로 생성하지 못하므로 유연하지 못하고 단위 테스트가 어려운 정적 메소드의 단점을 해결하고 있습니다.

 

라라벨 패키지 설치

외부에서 개발한 라라벨 패키지는 서비스 프로바이더 형식으로 제공하므로 서비스 프로바이더에 등록 해야하며 이를 사용하기 위해 파사드도 같이 등록해 주어야 합니다. 위에서 등록한  "intervention/image" 서비스 프로바이더를 Image 라는 파사드로 등록해 보겠습니다.

config/app.php

    'aliases' => [
        'App'       => Illuminate\Support\Facades\App::class,
		'Artisan'   => Illuminate\Support\Facades\Artisan::class,
		'Auth'      => Illuminate\Support\Facades\Auth::class,
		'Blade'     => Illuminate\Support\Facades\Blade::class,
		'Bus'       => Illuminate\Support\Facades\Bus::class,
		'Cache'     => Illuminate\Support\Facades\Cache::class,
		/* Image 파사드 등록*/
		'Image' => Intervention\Image\Facades\Image::class,
PHP

 

이제 이미지 서비스 프로바이더를 사용할 경우 다음과 같이 정적 메소드 방식을 통해 호출할 수 있습니다.

$img = Image::make('foo.jpg')->resize(320, 240)->insert('watermark.png');
CODE

 

프로젝트를 진행하면서 필요시마다 기본 프레임워크 이외의 외부 패키지를 사용할 것이며 패키지 설치시마다 위와 같이 config/app.php 에 서비스 프로바이더와 파사드를 추가하는 부분이 필요합니다.