728x90
의존성 주입은 크게 4가지 방법이 있다. 4가지 주입 방법과 어떤 방법을 사용하는 것이 바람직한지 알아보자
- 생성자 주입
- setter 주입
- 필드 주입
- 일반 메서드 주입
생성자 주입
- 생성자를 통해서 의존 관계를 주입하는 방법이다.
- 생성자 주입은 생성자 호출시점에 딱 1번만 호출되는 것이 보장된다.
- 변하지 않으며(불변), 반드시 필요한(필수) 의존관계에 사용한다.
@Component
public class ServiceImpl implements Service {
private final MemberRepository memberRepository;
// 생성자 주입
@Autowired // 생성자가 1개만 있으면 생략 가능(스프링에서만 가능)
pulic ServiceImpl(MemberRepository memberRepository) {
this.memberRepository = memberRepository;
}
}
setter 주입
- setter라 불리는 필드의 값을 변경하는 수정자 메서드를 통해서 의존관계를 주입하는 방법
- 변경 가능하며(변경), 선택적인 의존관계에서 사용한다.
@Component
public class ServiceImpl implements Service {
private MemberRepository memberRepository;
@Autowired
public void setMemberRepository(MemberRepository memberRepository) {
this.memberRepository = memberRepository;
}
}
필드 주입
- 필드에 바로 주입하는 방법
- 코드가 간결해지지만 외부에서 변경이 불가능하기때문에 테스트하기 어렵다는 단점이 있다.
- DI 프레임워크가 없으면 아무것도 할 수 없다.
- 스프링 설정을 목적으로 하는 @Configuration 같은 곳에서만 특별한 목적으로 사용한다.
- 왠만하면 사용하지 말자
@Component
public class ServiceImpl implements Service {
@Autowired
private MmeberRepository membeRepository;
}
일반 메서드 주입
- 일반 메서드를 통해 주입하는 방법
- 한 번에 여러 필드를 주입 받을 수 있다.
- 일반적으로 잘 사용하지 않는다.
@Component
public class ServiceImpl implements Service {
private MemberRepository memberRepository;
@Autowired
public void init(MemberRepository memberRepository) {
this.memberRepository = memberRepository;
}
}
생성자 주입을 사용하자!
과거에는 수정자 주입과 필드 주입을 많이 사용했지만, 최근에는 스프링을 포함한 DI 프레임워크 대부분이 생성자 주입을 권장한다.
왜 생성자 주입을 권장하는걸까?
불변
- 일반적으로 의존관계 주입은 한 번 일어나면 애플리케이션이 종료될 때까지 변경할 일이 없다. 오히러 대부분의 의존관계는 불변해야 한다.
- setter 주입을 사용하게 되면 메서드를 public으로 열어두어야 하기 때문에 누군가 실수로 코드를 변경할 수도 있고, 불변해야하는 메서드를 열어두는 것도 좋은 설계 방법이 아니다.
- 생성자 주입은 객체를 생성할 때 딱 1번만 호출된다. 이후에 호출되는 일이 없기 때문에 불변하게 설계할 수 있다.
누락
- 프레임워크가 없는 상태에서 주입 데이터가 누락되었을 때 setter 의존관계는 실행은 되지만 NPE(Null Point Exception)이 발생한다.
- 반면, 생성자 주입은 주입 데이터가 누락되어있으면 컴파일 오류가 발생한다. 그리고 IDE에서 어떤 값을 필수로 주입해야 하는지 알려준다.
final
- 생성자 주입은 필드에 final 키워드를 사용할 수 있다. 그래서 혹시라도 값이 설정되지 않는 오류를 컴파일 시점에서 알 수 있고 실행 전에 문제를 해결할 수 있다.
- 나머지 주입 방식(setter 주입, 필드 주입, 메서드 주입)은 모두 생성자 이후에 호출되기 때문에 필드에 final 키워드를 사용할 수 없다. 생성자 주입 방식만 fina 키워드를 사용 가능하다.
@Component
public class ServiceImpl implements Service {
private final MemberRepository memberRepository;
private final DiscountPolicy discountPolicy;
@Autowired
public ServiceImpl(MemberRepository memberRepository, DiscountPolicy
discountPolicy) {
// discountPolicy 필드 누락
this.memberRepository = memberRepository;
}
//...
}
// 컴파일 오류 발생
java: variable discountPolicy might not have been initialized
한 줄 정리
일반적으로는 생성자 주입을 사용하고 필수 값이 아닌 경우에 옵션으로 setter 주입을 사용하는 것이 좋다. (필드 주입과 메서드 주입은 사용하지 말자)
참고
728x90
'Spring' 카테고리의 다른 글
Spring - Spring으로 AWS S3에 이미지 업로드하기2: Spring에서 기능 구현 (0) | 2023.03.06 |
---|---|
Spring Security - OAuth2와 JWT로 로그인 구현하기(Kakao, Google, Naver) (4) | 2023.03.05 |
Spring - Scheduler로 매일 자정 실행되는 로직을 짜보자 (0) | 2023.03.02 |
Spring - No Offset 페이지네이션으로 페이징 성능을 개선해보자! (0) | 2023.02.28 |
Spring - 옵션 처리 3가지 방법 (0) | 2022.11.30 |