Laravel이 의존성 주입(Dependency Injection)을 효율적으로 관리하는 데 중심이 되는 도구
1. Service Container (서비스 컨테이너)
Service Container는 객체를 생성하고 관리하는 Laravel의 강력한 도구입니다. 쉽게 말해, "필요한 클래스를 자동으로 만들어서 주입해주는 박스"라고 볼 수 있습니다.
회사에서 회의를 할 때, 커피가 필요하다고 가정해 봅시다.
커피를 직접 만들기보다는, "커피를 주세요"라고 요청하면 알아서 커피가 옵니다.
여기서:
- "커피 주세요"는 클래스 요청
- 커피를 가져오는 직원은 Service Container
- 커피 제조법은 Service Provider가 등록해둔 레시피
Laravel에서는 __construct()에 클래스 타입을 지정하면, Service Container가 그 객체를 자동으로 만들어서 넣어줍니다.
class OrderController extends Controller
{
public function __construct(OrderService $service)
{
$this->service = $service;
}
}
→ OrderService 객체를 직접 만들지 않아도, Laravel이 알아서 생성해서 넣어줍니다.
2. Service Provider (서비스 프로바이더)
Service Provider는 Service Container에 "이 클래스를 어떻게 만들지", 즉 객체 생성 규칙을 등록하는 곳입니다.
"커피를 만들 때, 아메리카노는 이렇게 만들고, 라떼는 저렇게 만든다"라는 제조법(레시피)을 등록하는 장소입니다.
Laravel이 부팅(시작)될 때, 이 Service Provider들이 실행되며 컨테이너에 필요한 설정을 미리 등록해 둡니다.
AppServiceProvider.php의 register() 메서드에서 클래스 바인딩을 할 수 있습니다.
public function register()
{
$this->app->bind(
PaymentGatewayInterface::class,
StripePaymentGateway::class
);
}
이렇게 등록하면 Laravel은 PaymentGatewayInterface를 요청할 때 자동으로 StripePaymentGateway 객체를 생성해 줍니다.
Service Container :
- 의존성 자동으로 주입해주는 도구
- 커피를 전달해주는 직원
Service Provider :
- 객체 생성 방식을 정의하는 클래스
- 커피를 어떻게 만들지 정해둔 설명서
3. 동작방식 이해하기
Laravel의 Service Container가 OrderService 객체를 직접 만들지 않아도 자동으로 생성해주는 방식은 리플렉션(Reflection)과 자동 의존성 주입(Autowiring)을 기반으로 합니다. 이것을 이해하려면, Laravel이 클래스의 생성자(constructor)를 어떻게 분석하고, 거기에 필요한 의존성을 어떻게 주입하는지를 순서대로 살펴보아야 합니다.
Laravel이 객체를 자동으로 생성하는 과정
기본코드
class OrderController extends Controller
{
public function __construct(OrderService $service)
{
$this->service = $service;
}
}
1. 컨트롤러 호출 요청
- 사용자가 웹 브라우저에서 /orders를 요청하면, 라우터(Router)는 OrderController를 호출합니다.
- Laravel은 이때 OrderController 인스턴스를 생성해야 한다고 판단합니다.
2. Service Container가 클래스의 생성자를 분석
- Laravel은 PHP의 리플렉션(ReflectionClass) 기능을 사용해 OrderController 클래스의 생성자를 스캔합니다.
$reflection = new ReflectionClass(OrderController::class);
$constructor = $reflection->getConstructor();
- 생성자에 어떤 타입의 매개변수가 있는지를 확인합니다. 이 경우에는 OrderService.
3. 타입 힌트를 기준으로 필요한 객체 생성 시도
- Laravel은 OrderService가 클래스 타입이라는 것을 확인하고, 자신의 컨테이너에 OrderService가 등록되어 있는지 확인합니다.
- 등록되어 있다면 그 설정에 따라 객체를 생성하고,
- 등록되어 있지 않아도, 클래스가 생성 가능한 구조(= 의존성 있는 생성자 매개변수가 없거나, 다시 자동 생성 가능한 클래스들로 되어 있다면)일 경우 자동으로 재귀적으로 생성합니다.
4. OrderService의 의존성도 재귀적으로 주입
예를 들어 OrderService 클래스가 다음과 같이 정의되어 있다고 가정합니다.
class OrderService
{
public function __construct(PaymentService $payment)
{
$this->payment = $payment;
}
}
- Laravel은 또다시 OrderService의 생성자를 확인하고, PaymentService가 필요하다는 걸 파악합니다.
- 이 역시 같은 방식으로 생성합니다.
→ 이처럼 Laravel은 필요한 모든 의존성을 재귀적으로 자동 생성 및 주입하면서 객체를 완성해 나갑니다.
5. 컨트롤러 인스턴스를 최종 반환
- 모든 의존성 객체를 생성한 후, OrderController에 OrderService 객체를 주입하여 최종 인스턴스를 생성합니다.
$orderController = new OrderController(new OrderService(new PaymentService));
물론 실제로는 이 과정을 전부 자동으로 처리하므로 개발자는 new 키워드를 직접 쓸 필요가 없습니다.
자동 생성이 가능한 이유는?
Laravel이 이 기능을 제공할 수 있는 이유는 다음과 같습니다:
- PHP의 ReflectionClass와 ReflectionParameter를 활용해 클래스 정보를 분석
- Illuminate\Container\Container 클래스가 build() 메서드 안에서 이 로직을 처리
- 클래스가 인터페이스를 구현했거나 추상 클래스일 경우, 서비스 프로바이더에서 구체 클래스를 등록해주어야 자동 주입이 가능
4. Service Container 생성시점
Laravel의 Service Container 인스턴스는 Laravel 애플리케이션의 부팅(Bootstrapping) 과정에서 매우 이른 시점에 생성됩니다. Laravel에서 이 Service Container는 단순한 도구가 아니라 애플리케이션의 핵심 구조 자체라고 볼 수 있습니다. 언제, 어떻게 생성되는지를 정확히 이해하면 Laravel의 작동 원리를 더 깊이 알 수 있습니다.
Service Container는 Laravel 애플리케이션이 시작되자마자 가장 먼저 생성되는 핵심 객체 중 하나입니다.
- public/index.php 실행
- bootstrap/app.php에서 $app 객체 생성 → 바로 이 $app이 Service Container 인스턴스
- 이후 이 $app 객체가 전체 프레임워크의 중심이 됨 (서비스 프로바이더 등록, 커널 실행 등)
단계별 설명
1. public/index.php – Laravel의 진입점
require __DIR__.'/../bootstrap/app.php';
- Laravel의 모든 요청은 이 파일을 통해 시작되며,
- 이 파일에서 Laravel 애플리케이션을 부팅하는 $app 객체를 가져옵니다.
2. bootstrap/app.php – $app 객체 생성
$app = new Illuminate\Foundation\Application(
$_ENV['APP_BASE_PATH'] ?? dirname(__DIR__)
);
- 여기서 Application 클래스의 인스턴스를 생성합니다.
- 이 클래스는 Illuminate\Container\Container를 상속합니다.
- 즉, $app 객체는 Service Container의 인스턴스입니다.
3. Service Container는 이때 이미 사용 가능
return $app;
- bootstrap/app.php는 $app을 반환하며,
- 이후 이 $app 인스턴스를 통해 Kernel이 실행되고, 라우팅, 미들웨어, 서비스 프로바이더 등록 등이 이루어집니다.
- 모든 서비스 바인딩과 싱글톤, 서비스 주입은 이 $app 컨테이너에 등록 및 주입됩니다.
내부 구조 참고
class Application extends Container implements ApplicationContract
- Illuminate\Foundation\Application 클래스는 Laravel의 메인 애플리케이션 클래스이며,
- Illuminate\Container\Container를 상속하므로, Service Container의 기능을 그대로 내장하고 있습니다.
5. Service Provider에서 등록된 바인딩 확인 (커피 레시피 등록 및 확인하기)
app/Providers/*.php
App\Providers\AppServiceProvider
App\Providers\AuthServiceProvider
App\Providers\RouteServiceProvider
1) AppServiceProvider.php 에 등록하기
public function register()
{
$this->app->bind(SomeInterface::class, SomeClass::class);
$this->app->singleton('key', function () { return new SomeClass(); });
}
위 코드처럼 register() 메서드에서 Service Container에 명시적으로 바인딩됩니다.
register() 메서드
- 서비스(클래스)를 컨테이너에 바인딩하는 역할을 합니다.
- 싱글톤, 인터페이스 ↔ 구현체 바인딩 등 서비스 컨테이너의 초기 구성을 담당합니다.
- Laravel 애플리케이션이 부팅되기 전에 먼저 실행됩니다.
- 이 시점에는 서비스가 아직 실행되지 않았고, 라우팅도 처리되지 않은 상태입니다.
public function register()
{
// 인터페이스 ↔ 구현체 바인딩
$this->app->bind(
\App\Contracts\OrderServiceInterface::class,
\App\Services\OrderService::class
);
// 싱글톤 등록
$this->app->singleton('currency', function () {
return new \App\Helpers\CurrencyHelper();
});
}
boot() 메서드
- 애플리케이션이 완전히 부팅된 후 실행되는 후처리 작업을 담당합니다.
- 서비스 바인딩 이후에, 실제 상태 초기화나 이벤트 리스너 등록, 전역 설정 등을 처리합니다.
- register() 메서드들이 모두 실행된 후, Laravel이 서비스를 모두 준비한 다음 실행됩니다.
public function boot()
{
// 뷰 composer 등록
View::composer('partials.sidebar', function ($view) {
$view->with('categories', Category::all());
});
// 전역 문자열 포맷 설정
Carbon::setLocale('ko');
// 커스텀 Blade 디렉티브 등록
Blade::directive('datetime', function ($expression) {
return "<?php echo ($expression)->format('Y-m-d H:i'); ?>";
});
}
2) config/app.php → 'providers' 배열
'providers' => [
Illuminate\Auth\AuthServiceProvider::class,
Illuminate\Broadcasting\BroadcastServiceProvider::class,
// ...
]
이 배열은 Laravel이 부팅하면서 로드하는 서비스 프로바이더 목록입니다. 여기 등록된 각 Provider에서 register() 또는 boot() 메서드를 통해 컨테이너에 바인딩이 수행됩니다.
- public/index.php 실행
- bootstrap/app.php에서 $app = new Application(...) 생성
- $kernel->bootstrap() 호출
- Illuminate\Foundation\Bootstrap\LoadConfiguration 클래스 실행 ← 여기서 config/*.php 읽힘
3) ServiceProvider::defaultProviders()
ServiceProvider::defaultProviders()는 Laravel의 핵심 프레임워크 내부에서 사용하는 정적 메서드로, Laravel이 부팅(bootstrap)할 때 자동으로 로드하는 기본 서비스 프로바이더 목록을 정의합니다.
이 메서드는 사용자 애플리케이션 코드에는 잘 드러나지 않지만, Laravel 프레임워크의 내부 부트스트래핑 로직에서 매우 중요한 역할을 합니다.
protected static function defaultProviders(): array
{
return [
Illuminate\Auth\AuthServiceProvider::class,
Illuminate\Broadcasting\BroadcastServiceProvider::class,
Illuminate\Bus\BusServiceProvider::class,
Illuminate\Cache\CacheServiceProvider::class,
Illuminate\Foundation\Providers\ConsoleSupportServiceProvider::class,
// 기타 Laravel의 핵심 서비스들...
];
}
-> 이 메서드는 Laravel의 핵심 기능을 지원하기 위한 기본 서비스 프로바이더 집합을 반환합니다.
'Laravel' 카테고리의 다른 글
| Laravel 전용 MCP 서버 - boost (2) | 2025.08.17 |
|---|---|
| Livewire 와 Alpine.js 개념잡기 (3) | 2025.08.17 |
| Laravel Pint란? (0) | 2025.03.28 |
| Mailpit - 로컬PC 에서 SMTP 테스트하기 (0) | 2025.02.07 |
| Docker 에서 Laravel 개발하기 (0) | 2025.01.28 |