✏️DI(Dependency Injection) 이란?
IoC 의 구현 방법 중 하나로, 객체가 의존하는 다른 객체를 외부에서 주입받는 방법.
DI 를 사용하면 객체가 자신의 의존성을 직접 생성하지 않고, 프레임워크나 컨테이니가 의존성을 주입
📌 DI 주요 장점 :
- 유연성 : 의존성을 외부에서 주입받기 때문에, 의존성의 교체가 용이하고, 모듈화된 구조를 유지할 수 있음.
- 테스트 용이성 : 의존성을 모의 객체로 쉽게 대체할 수 있어 유닛 테스트가 용이
- 구성 관리 : 객체의 구성과 생명 주기 관리를 프레임워크가 당당하여 애플리케이션의 복잡성을 줄임
DI의 주요 방법
- 💻생성자 주입 : 생성자를 통해 의존성을 주입
👉 생성자 주입 은 클래스의 생성자를 통해 의존성을 주입받는 방식.
생성자가 호출될 때 필요한 의존성을 모두 주입받기 때문에 객체가 완전히 초기화 된 상태에서 사용됨
👉 장점 :
- 불변성 : 객체가 생성될 때 의존성이 모두 주입되므로 객체의 상태가 불변이 됨. 이는 객체의 불완전 상태를 방지하고 안정성을 높임
- 필수 의존성 : 생성자 주입은 필수 의존성을 명확히 선언할 수 있음. 생성자가 호출될 때 필요한 모든 의존성이 제공되므로, 의존성이 없는 상태에서 객체가 생성되는 것을 방지
- 테스트 용이성 : 테스트할 때 필요한 의존성을 생성자 인자로 전달하기 때문에 테스트가 간편
public class MyService {
private final MyRepository myRepository;
@Autowired
public MyService(MyRepository myRepository) {
this.myRepository = myRepository;
}
}
- 💻세터 주입 : 세터 메서드를 통해 의존성을 주입
👉 세터 주입 은 세터(Setter) 메서드를 통해 의존성을 주입받는 방식.
의존성 주입이 필요할 때 세터 메서드를 호출하여 의존성을 설정
👉 장점 :
- 선택적 의존성 : 의존성을 선택적으로 주입할 수 있음. 생성자 주입과 달리 선택적이며, 나중에 의존성을 설정할 수 있음.
- 재설정 기능 : 세터 메서드를 통해 의존성을 재설정할 수 있음
👉 단점 :
- 불완전 상태 : 객체가 생성된 후에 의존성이 주입되기 때문에, 객체가 불완전한 상태로 존재할 수 있음. 이로 인해 예상치 못한 문제가 발생할 수 있음.
- 의존성 누락 가능성 : 의존성이 주입되지 않으면 객체가 제대로 동작하지 않을 수 있음. 세터 주입은 필수 의존성 확인이 어려움
public class MyService {
private MyRepository myRepository;
@Autowired
public void setMyRepository(MyRepository myRepository) {
this.myRepository = myRepository;
}
}
- 💻 필드 주입 : 필드에 직접 의존성을 주입.
권장되지는 않음
👉 필드 주입 은 필드에 직접 의존성을 주입받는 방식.
주입할 필드에 @Autowired 를 붙여서 의존성을 자동으로 주입받음
👉 장점 :
- 간편함 : 코드가 간단하고, 주입받을 의존성을 생성자나 세터를 통해 주입받을 필요가 없으므로 간편
👉 단점 :
- 테스트 어려움 : 필드 주입은 테스트 시 필드에 직접 접근할 수 없기 때문에 테스트를 설정하는 데 어려움이 있음.
테스트하기 위해서는 리플렉션을 사용하거나, 별도의 테스트 지원 도구가 필요할 수 있음.
- 불변성 : 필드 주입은 객체가 생성된 후에 의존성이 주입되기 때문에, 객체가 불완전한 상태로 존재할 수 있음. 이는 객체의 상태가 예측할 수. 없게 됨
- 캢슐화 위반 : 필드에 직접 접근하는 것은 객체의 캡슐화를 위반할 수 있으며, 객체의 내부 구조에 대한 의존성을 만들 수 있음. 이로 인해 코드의 유지보수성이 떨어질 수 있음.
public class MyService {
@Autowired
private MyRepository myRepository;
}