의존성 주입(Dependecy Injection, DI)은 객체가 필요로 하는 의존성(즉, 협력 객체들)을 외부에서 제공하는 방식을 말합니다. 이를 통해 객체는 자신의 의존성을 직접 생성하거나 검색하지 않고, 필요한 의존성을 주입받아 사용할 수 있습니다. 이러한 방법은 코드의 결합도를 낮추고, 유연성 및 재사용성을 높이며, 테스트 용이성을 개선합니다.
DI의 주요 유형
생성자 주입(Constructor Injection):
- 객체 생성 시 생성자를 통해 의존성을 주입합니다.
- 주입받는 객체가 불변하며, 필수 의존성을 갖습니다.
- 순환 의존성을 컴파일 시간에 잡을 수 있으며, 객체의 완전한 초기화를 보장합니다.
public class Car {
private final Engine engine;
public Car(Engine engine) {
this.engine = engine;
}
public void start() {
engine.start();
}
}
세터 주입(Setter Injection):
- 세터 메소드를 통해 의존성을 주입합니다.
- 선택적 의존성 주입에 유용하며, 객체 생성 후 의존성을 변경할 수 있습니다.
- 생성자 주입에 비해 덜 엄격하므로 의존성이 명확하지 않을 수 있습니다.
public class Car {
private Engine engine;
@Autowired
public void setEngine(Engine engine) {
this.engine = engine;
}
public void start() {
engine.start();
}
}
필드 주입(Field Injection):
- 직접 클래스의 필드에 의존성을 주입합니다.
- 코드는 간결해지지만, 테스트와 코드의 이해가 어려울 수 있으며, 순환 의존성 문제가 발생할 수 있습니다.
- 외부에서 직접 필드를 변경할 수 없기 때문에 테스트가 어렵습니다.
public class Car {
@Autowired
private Engine engine;
public void start() {
engine.start();
}
}
@RequiredArgsConstructor 롬복
- 최종(final) 필드 또는 ‘@NonNull’ 어노테이션이 붙은 필드에 대한 생성자를 자동으로 생성해줍니다. 이러헥 자동 생성된 생성자를 통해 스프링 의존성을 주입할 수 있습니다.
@RequiredArgsConstructor
public class Car {
private final Engine engine;
public void start() {
engine.start();
}
}
Lombok은 다음과 같은 생성자를 자동으로 생성합니다.
public Car(Engine engine) {
this.engine = engine;
}
참고) @Component 어노테이션을 사용함으로써, 개발자는 객체의 생성과 생명주기를 스프링 컨테이너에 위임하고, 의존성 관리를 자동화하여 애플리케이션의 결합도를 낮추고 유지보수성을 향상시킬 수 있습니다.
DI 차이점
생성자 주입(Constructor Injection)
- 불변성 보장: 생성자를 통해 의존성을 주입받은 객체는 불변의 성격를 가지게 되어, 생성 후에는 의존성을 변경할 수 없습니다. 이는 애플리케이션의 안정성을 높여줍니다.
- 순환 참조 방지: 생성자 주입을 사용하면 순환 참조를 컴파일 시점에서 발견할 수 있으며, 이는 애플리케이션의 구조적인 문제를 조기에 감지할 수 있는 장점이 있습니다.
세터 주입(Setter Injection)
- 선택적 의존성: 세터 주입은 의존성이 필수적이지 않거나 애플리케이션 실행 중에 변경될 수 있는 경우에 유용합니다. 이 방식은 객체가 완전히 초기화되지 않은 상태로 사용될 위험도 있지만, 적절하게 관리된다면 유연한 의존성 관리가 가능합니다.
필드 주입(Field Ingection)
- 편의성: 필드 주입은 간단하게 의존성을 주입할 수 있으며, 코드를 더 간결하게 만들어 줍니다. 하지만 이 방식은 테스트와 코드 유지보수 측면에서 여러 단점을 가지고 있습니다.
- 테스트의 어려움: 필드 주입은 테스트 환경 구성 시, 스프링 컨테이너 없이는 의존성을 주입하기 어려워, 순수 자바 코드만으로 단위 테스트를 작성하기가 어렵습니다.
❗️생성자 주입을 사용할 때 필드를 ‘final’로 선언하는 것을 필수는 아니지만, 클래스의 안정성과 불변성을 향상시키는 데 매우 유용합니다. 이는 객체의 생명주기 동안 의존성이 변경되지 않음을 보장합니다.
❗️ @RequiredArgsConstructor 어노테이션을 사용하는 것은 스프링 개발에서 의존성 주입을 다룰 때 매우 안전하고 효율적인 방법 중 하나입니다. Lombok 라이브러리의 **@RequiredArgsConstructor**는 자동으로 final필드나 @NonNull 어노테이션이 붙은 필드에 대해 생성자를 생성해주기 때문에, 명시적으로 생성자를 작성할 필요 없이 의존성 주입을 보장합니다.
결론) DI(의존성 주입)에는 생성자 주입, 세터 주입, 필드 주입이 있습니다. 생성자 주입은 모든 의존성을 객체 생성 시 한 번에 주입받아 불변성과 필수 의존성을 보장합니다. 가장 안정적인 권장되는 방식이며 세터 주입은 의존성을 변경할 수 있는 유연성을 제공하며 선택적 의존성에 적합합니다. 필드 주입은 코드를 간결하게 만들지만 테스트와 스프링 외부에에서의 사용이 어렵습니다.
'스터디 > Victor' 카테고리의 다른 글
[Git ] 깃헙 프로젝트와 이슈 정리하기 (0) | 2024.05.26 |
---|---|
[Spring Boot] 인텔리제이 설정 및 플러그인 (0) | 2024.05.26 |
[Spring Boot] Springdoc-OpenApi ( Swagger ) (0) | 2024.05.26 |
[Spring Boot] 스프링 부트 Response Entity (1) | 2024.05.26 |
시간 복잡도 (0) | 2024.04.08 |