의존성 주입(DI, Dependency Injection)은 객체가 필요한 의존성을 스스로 생성하지 않고 외부에서 전달받는 설계 패턴이다. 결합도를 낮추고 테스트와 교체가 쉬운 코드를 만든다.
의존성 주입이 없을 때
python
# 나쁜 예: Service가 Repository를 직접 생성
class UserService:
def __init__(self):
self.repo = MySQLUserRepository() # 강결합
# 테스트 시 실제 DB가 필요, Mock 불가
# DB를 PostgreSQL로 바꾸려면 UserService 수정 필요
생성자 주입 (Constructor Injection)
python
from abc import ABC, abstractmethod
class UserRepository(ABC):
@abstractmethod
def find_by_id(self, id: int): ...
class MySQLUserRepository(UserRepository):
def find_by_id(self, id): ...
class UserService:
def __init__(self, repo: UserRepository): # 외부에서 주입
self.repo = repo
# 운영 코드
service = UserService(MySQLUserRepository())
# 테스트 코드 (Mock 사용 가능)
class MockUserRepo(UserRepository):
def find_by_id(self, id): return User(id, "test")
service = UserService(MockUserRepo())
DI 컨테이너 (Spring, FastAPI)
python
# FastAPI Depends
from fastapi import Depends
def get_db():
db = SessionLocal()
try:
yield db
finally:
db.close()
@app.get("/users/{id}")
async def get_user(id: int, db: Session = Depends(get_db)):
return db.query(User).filter(User.id == id).first()
java
// Spring @Autowired
@Service
public class UserService {
private final UserRepository repo;
@Autowired // Spring이 자동으로 Repository 주입
public UserService(UserRepository repo) {
this.repo = repo;
}
}
주입 유형
| 유형 | 방식 | 장단점 |
|---|
| 생성자 주입 | 생성자 파라미터 | 불변 객체, 필수 의존성 명확 (권장) |
| 세터 주입 | setter 메서드 | 선택적 의존성 가능 |
| 필드 주입 | 어노테이션 (@Autowired) | 간결하지만 테스트 어려움 |
관련 개념