Skip to content

Dependency Injection

Container

Container는 싱글톤 레지스트리다. 모든 provider를 등록 순서대로 관리하며, lifecycle 메서드를 순서대로 호출한다.

ts
import { Container } from '@repo/electron-ipc';

const container = new Container({
  onError: (name, error) => console.error(`[${name}]`, error),
});

container.register(UserService);
container.register(AuthService);
container.resolveAll();

TIP

일반적으로 Container를 직접 사용할 필요 없다. createApp()이 내부적으로 Container를 생성하고 모듈의 provider를 등록한다.

주요 메서드

메서드설명
register(token)@Injectable 표시된 클래스를 등록
resolve(token)싱글톤으로 인스턴스 반환 (첫 호출 시 생성)
createInstance(cls)레지스트리에 등록하지 않는 일회성 인스턴스 생성
resolveAll()등록된 모든 provider를 등록 순서대로 eagerly resolve
initAll()onInit() 구현체를 순서대로 호출
attachWindowAll(window)onWindowAttach() 구현체를 순서대로 호출
disposeAll()onDispose() 구현체를 순서대로 호출

ContainerOptions

필드타입설명
onError(name: string, error: unknown) => voidlifecycle 실행 중 에러 콜백. 에러가 발생해도 나머지 provider는 계속 실행된다.

inject()

inject()는 클래스 필드 이니셜라이저에서 의존성을 주입하는 함수다. Angular 14+의 inject() 패턴을 따른다.

ts
@Injectable()
class AuthService {
  private readonly userService = inject(UserService);
  private readonly tokenService = inject(TokenService);

  authenticate(token: string) {
    const decoded = this.tokenService.verify(token);
    return this.userService.findById(decoded.userId);
  }
}

동작 원리

  1. Container가 인스턴스를 생성할 때 전역 activeContainer를 자신으로 설정한다
  2. 클래스 생성자가 실행되면서 필드 이니셜라이저의 inject() 호출이 activeContainer에서 의존성을 resolve한다
  3. 중첩 inject()도 지원된다 — A가 B를 주입하고, B가 C를 주입하는 경우

WARNING

inject()는 반드시 Container의 인스턴스 생성 컨텍스트 안에서 호출해야 한다. 컨텍스트 밖에서 호출하면 에러가 발생한다.

Lifecycle 인터페이스

provider는 선택적으로 lifecycle 인터페이스를 구현할 수 있다. 모든 lifecycle 메서드는 등록 순서대로 호출된다.

OnInit

윈도우 생성 에 호출된다. 설정 로드, 데이터베이스 연결 등 초기화 작업에 사용한다.

ts
import { Injectable, type OnInit } from '@repo/electron-ipc';

@Injectable()
class DatabaseService implements OnInit {
  private db!: Database;

  onInit() {
    this.db = new Database('./app.db');
  }
}

OnWindowAttach

윈도우 생성 호출된다. 윈도우 참조가 필요한 작업에 사용한다.

ts
import { Injectable, type OnWindowAttach } from '@repo/electron-ipc';
import type { BrowserWindow } from 'electron';

@Injectable()
class TrayService implements OnWindowAttach {
  onWindowAttach(window: BrowserWindow) {
    // 트레이 아이콘 클릭 시 윈도우 토글
  }
}

OnDispose

윈도우 closed 이벤트 시 호출된다. 리소스 정리에 사용한다.

ts
import { Injectable, type OnDispose } from '@repo/electron-ipc';

@Injectable()
class DatabaseService implements OnDispose {
  onDispose() {
    this.db.close();
  }
}

Lifecycle 실행 순서

resolveAll()     → 모든 provider 인스턴스 생성
initAll()        → OnInit.onInit() 호출
                 → createWindow()
attachWindowAll()→ OnWindowAttach.onWindowAttach() 호출
                 → IPC 핸들러 등록
disposeAll()     → OnDispose.onDispose() 호출 (윈도우 closed 시)

각 단계에서 에러가 발생하면 onError 콜백이 호출되고, 나머지 provider의 lifecycle은 계속 실행된다.

다음 단계