Files
2nd/10_Wiki/Topics/Architecture/Dependency Injection (의존성 주입).md
T
2026-05-10 22:08:15 +09:00

176 lines
5.0 KiB
Markdown

---
id: wiki-2026-0508-dependency-injection-의존성-주입
title: Dependency Injection (의존성 주입)
category: 10_Wiki/Topics
status: verified
canonical_id: self
aliases: [DI, Dependency Injection, IoC, Inversion of Control]
duplicate_of: none
source_trust_level: A
confidence_score: 0.93
verification_status: applied
tags: [di, ioc, design-pattern, spring, nestjs]
raw_sources: []
last_reinforced: 2026-05-10
github_commit: pending
tech_stack:
language: typescript
framework: nestjs
---
# Dependency Injection (의존성 주입)
## 매 한 줄
> **"매 의존성 매 외부 주입, 직접 생성 X"**. IoC 의 가장 흔한 구현. Martin Fowler (2004) 가 명명. 2026 현재 Spring (Java), NestJS (Node), Angular, dagger (Android), wire (Go) 매 mainstream; testability + decoupling 의 backbone.
## 매 핵심
### 매 형태 (3 종류)
- **Constructor injection** — 생성자 매 dependency 받음. 매 immutable, 매 권장.
- **Setter injection** — setter 매 dependency 받음. optional dep 에 적합.
- **Field injection** — 매 framework 의 reflection. simple 하지만 testability ↓.
### 매 benefit
- **Testability** — mock 매 쉽게 inject.
- **Decoupling** — concrete impl 의 unaware.
- **Lifecycle 관리** — singleton, request-scoped, transient.
- **Configuration centralization** — DI container 의 wiring.
### 매 응용
1. Spring `@Autowired`, `@Component`.
2. NestJS `@Injectable()` + module providers.
3. Angular `providedIn: 'root'`.
4. Go: 매 manual 또는 google/wire codegen.
## 💻 패턴
### NestJS — constructor injection
```typescript
@Injectable()
export class UserService {
constructor(
private readonly repo: UserRepository,
private readonly logger: Logger,
) {}
async find(id: string) {
this.logger.log(`finding ${id}`);
return this.repo.findById(id);
}
}
@Module({
providers: [UserService, UserRepository, Logger],
exports: [UserService],
})
export class UserModule {}
```
### Spring Boot — constructor injection (no `@Autowired` needed)
```java
@Service
public class OrderService {
private final PaymentGateway gateway;
private final OrderRepository repo;
public OrderService(PaymentGateway gateway, OrderRepository repo) {
this.gateway = gateway;
this.repo = repo;
}
}
```
### Token / interface binding (NestJS)
```typescript
export const PAYMENT_GATEWAY = Symbol('PAYMENT_GATEWAY');
@Module({
providers: [
{ provide: PAYMENT_GATEWAY, useClass: StripeGateway },
],
exports: [PAYMENT_GATEWAY],
})
export class PaymentModule {}
@Injectable()
class CheckoutService {
constructor(@Inject(PAYMENT_GATEWAY) private gw: PaymentGateway) {}
}
```
### Factory provider (async, e.g. DB connection)
```typescript
{
provide: 'DATABASE_CONNECTION',
useFactory: async (config: ConfigService) => {
return await createPool({ url: config.get('DB_URL') });
},
inject: [ConfigService],
}
```
### Manual DI (Go, wire-style)
```go
// wire.go (codegen)
func InitializeApp() *App {
repo := NewUserRepo(NewDB())
svc := NewUserService(repo)
return NewApp(svc)
}
```
### Test with mock (vitest)
```typescript
const mockRepo: UserRepository = {
findById: vi.fn().mockResolvedValue({ id: '1', name: 'A' }),
};
const service = new UserService(mockRepo, mockLogger);
expect(await service.find('1')).toEqual({ id: '1', name: 'A' });
```
### Modern: TC39 decorators + Reflect.metadata (2026)
```typescript
@injectable()
class EmailService {
@inject(SMTP_CLIENT) private smtp!: SmtpClient;
}
```
## 매 결정 기준
| 상황 | Approach |
|---|---|
| Spring/Java | `@Component` + constructor injection |
| Node.js/TS, full framework | NestJS module providers |
| Frontend (Angular) | `providedIn: 'root'` |
| Go | manual or `google/wire` |
| Tiny app, no framework | manual constructor — DI 불필요 |
**기본값**: constructor injection, framework-managed singleton. Field injection 매 피하기.
## 🔗 Graph
- 부모: [[Inversion of Control]] · [[SOLID]] (D)
- 변형: [[Service Locator]] · [[Factory Pattern]]
- 응용: [[Spring Framework]] · [[NestJS]] · [[Angular]]
- Adjacent: [[Cross-Cutting Concerns]] · [[Aspect-Oriented Programming (AOP)]]
## 🤖 LLM 활용
**언제**: provider wiring 생성, mock 매 test 자동 생성, refactor field→constructor injection.
**언제 X**: lifecycle / scope decision 매 architectural taste 필요.
## ❌ 안티패턴
- **Service Locator** — DI 와 혼동, dep 매 hidden.
- **Field injection 남용** — test 시 reflection 필요, 매 fragile.
- **Circular dep** — A→B→A. forwardRef 로 hack 보다 redesign.
- **God container** — singleton 매 200개. module boundary 무시.
- **`new` in business logic** — DI 의 의미 없음.
## 🧪 검증 / 중복
- Verified (Fowler 2004 *Inversion of Control Containers and the Dependency Injection Pattern*, NestJS docs 2026).
- 신뢰도 A.
## 🕓 Changelog
| 날짜 | 변경 |
|---|---|
| 2026-05-08 | Phase 1 |
| 2026-05-10 | Manual cleanup — full content with NestJS/Spring/Go patterns |