DI란?
의존성 주입(외부에서 두 객체 간의 관계를 결정해주는 디자인 패턴), 객체를 직접 생성하는 게 아니라 외부에서 생성한 후 주입하는 방식
과정
A 객체에서 B, C 객체를 의존할 때, A 객체에서 B, C 객체를 직접 생성하는 것이 아니라 외부(IoC 컨테이너)에서 생성된 객체를 주입
인터페이스를 사이에 둬서 클래스 레벨에서는 의존관계가 고정되지 않도록 하고 런타임 시에 관계를 동적으로 주입하여 유연성을 확보하고 결합도를 낮춤
객체 자체가 코드 상에서 객체 생성에 관여하지 않아도 돼서 객체 사이의 의존도 낮출 수 있음
DI(의존성 주입) 3가지 방법
1. 생성자 주입
@Controller
public class PetController{
private final PetService petService;
@Autowired
public PetController(PetService petService){
this.petService = petService;
}
}
/////////////////////////////////////////////////
// @Autowired 생략 & Lombok 사용 (생성자 생략 가능)
@Controller
@RequiredArgsConstructor
public class PetController{
private final PetService petService;
}
클래스의 생성자를 통해 의존성 주입
생성자 주입은 인스턴스가 생성될 때 1회 호출 보장, 필드에 final 키워드 사용 가능
@Autowired (Spring 4.3부터 생략 가능)
Lombok 라이브러리의 @RequiredArgsConstructor (final 붙은 주입에만 가능)활용하여 생성자 생략 가능
final 키워드를 사용하지 않으면 @AllArgsConstructor 사용
Spring 공식 문서에서 권장, final 키워드 사용으로 객체의 불변성 보장
2. 필드 주입
@Controller
public class PetController{
@Autowired
private PetService petService;
}
클래스에 선언된 필드에 생성된 객체를 주입
[문제점]
- final 키워드 사용 불가 -> 불변성 보장 X (생성자 이후에 호출되서 final 키워드 사용 X)
- 클래스 외부에서 접근이 불가능해서 테스트하기 어려움
- 단일 책임 원칙 위반
- 주입이 동시에 일어나 겹치는 경우, 순환참조 에러 발생
순환 의존이란 서로 다른 클래스가 서로를 참조하게 되는 상황이다. Class A가 Class B의 객체를 이용하고 Class B가 Class A의 객체를 이용하게 되면, 서로의 객체가 생성되지 않아 콜스택이 쌓이다 결국 오버플로우를 발생시킨다.
이는 다른 의존 주입을 통해서도 발생할 수 있지만 Field Injection은 의존하고 있는 객체가 생성되지 않아도 의존받는 객체가 생성될 수 있어 컴파일 단계에서는 문제가 없다. 결국 런타임 단계까지 가서 순환 참조를 잡아낼 수 있기 때문에 매우 곤란해질 수 있다.
3. Setter 주입
@Controller
public class PetController{
private PetService petService;
@Autowired
public void setPetService(PetService petService){
this.petService = petService;
}
}
setter or 사용자 정의 메서드를 통해 의존 관계 주입
[문제점]
- final 키워드 사용 불가 -> 불변성 보장 X (생성자 이후에 호출되서 final 키워드 사용 X)
'CS' 카테고리의 다른 글
[CS] Spring Interceptor (0) | 2024.04.30 |
---|---|
[CS] Spring Filter (0) | 2024.04.30 |
[CS] Spring에서 Bean 등록하는 방법 (0) | 2024.04.29 |
[CS 스터디] Spring (0) | 2024.04.29 |
[CS 스터디] Java(자바) (0) | 2024.04.17 |