과거에는 수정자 주입과 필드 주입을 많이 사용했지만, 최근에는 스프링을 포함한 DI 프레임워크 대부분이
생성자 주입을 권장한다.
1. 불변
- 대부분의 의존관계 주입은 한번 일어나면 애플리케이션 종료 시점까지 의존관계를 변경할 일이 없다. 오히려 대부분의 의존관계는 애플리케이션 종료 전까지 변하면 안된다.(불변해야 한다.)
- 수정자 주입을 사용하면, setXxx 메서드를 public으로 열어두어야 한다. -> 누군가 실수로 변경할 수 도 있고, 변경하면 안 되는 메서드를 열어두는 것은 좋은 설계 방법이 아니다.
- 생성자 주입은 객체를 생성할 때 딱 1번만 호출되므로 이후에 호출되는 일이 없다. 따라서 불변하게 설계할 수 있다.
2. 누락
테스트 코드 작성시(순수 자바 코드)
생성자 주입을 사용하면 다음처럼 주입 데이터를 누락했을 때 컴파일 오류가 발생한다.
그리고 IDE에서 바로 어떤 값을 필수로 주입해야 하는지 알 수 있다.
아래 코드에서는 new OrderServiceImple에서 컴파일 오류가 발생한다.
@Test
void createOrder() {
OrderServiceImpl orderService = new OrderServiceImpl();
orderService.createOrder(1L, "itemA", 10000);
}
3. final 키워드
생성자 주입을 사용하면 필드에 final 키워드를 사용할 수 있다. 그래서 생성자에서 혹시라도 값이
설정되지 않는 오류를 컴파일 시점에 막아준다.
** 컴파일 오류는 세상에서 가장 빠르고, 좋은 오류다!
* 참고: 수정자 주입을 포함한 나머지 주입 방식은 모두 생성자 이후에 호출되므로, 필드에 final 키워드를
사용할 수 없다. 오직 생성자 주입 방식만 final 키워드를 사용할 수 있다.
4. 정리
- 생성자 주입 방식을 선택하는 이유는 여러 가지가 있지만, 프레임워크에 의존하지 않고, 순수한 자바 언어의 특징을 잘 살리는 방법이기도 하다.
- 기본으로 생성자 주입을 사용하고, 필수 값이 아닌 경우에는 수정자 주입 방식을 옵션으로 부여하면 된다.
- 생성자 주입과 수정자 주입을 동시에 사용할 수 있다.
- 항상 생성자 주입을 선택해라! 그리고 가끔 옵션이 필요하면 수정자 주입을 선택해라. 필드 주입은 사용하지 않는 게 좋다.
5. 롬복과 최신 트렌드
요약: 롬복 세팅 후 @RequiredArgsConstructor 사용하여 생성자 주입
5-1) 세팅
- 롬복 플러그인 설치
- Settings - Compiler - Annotation Processors - Enable annotation processing 추가
- build.gradle 코드 추가
# 프로잭트 생성시 lombok 라이브러리 추가하면 자동 생성
configurations {
compileOnly {
extendsFrom annotationProcessor
}
}
dependencies {
//lombok 라이브러리 추가 시작
compileOnly 'org.projectlombok:lombok' # 프로잭트 생성시 lombok 라이브러리 추가하면 자동 생성
annotationProcessor 'org.projectlombok:lombok'
testCompileOnly 'org.projectlombok:lombok'
testAnnotationProcessor 'org.projectlombok:lombok'
//lombok 라이브러리 추가 끝
}
@RequiredArgsConstructor
- 생성자 코드를 자동으로 생성해주므로 코드가 간결해진다.
- final 변수 추가 시에 추가 작업이 필요치 않다
# 예시코드
@RequiredArgsConstructor // final이 붙으면 필수 값이됨 -> 필수 생성자를 생성해줌
@Component
public class OrderServiceImpl implements OrderService {
private final MemberRepository memberRepository;
private final DiscountPolicy discountPolicy;
//@RequiredArgsConstructor가 생성해줌
// public OrderServiceImpl(MemberRepository memberRepository, DiscountPolicy discountPolicy) {
// this.memberRepository = memberRepository;
// this.discountPolicy = discountPolicy;
// }
@Override
public Order createOrder(Long memberId, String itemName, int itemPrice) {
Member member = memberRepository.findById(memberId);
int discountPrice = discountPolicy.discount(member, itemPrice);
return new Order(memberId, itemName, itemPrice, discountPrice);
}
}
정리
최근에는 생성자를 딱 1개 두고, @Autowired를 생략하는 방법을 주로 사용한다.
여기에 Lombok 라이브러리의 @RequiredArgsConstructor 함께 사용하면 기능은 다 제공하면서, 코드는 깔끔하게 사용할 수 있다.
'프로그래밍 > Spring' 카테고리의 다른 글
애노테이션 직접 만들기 (@Qualifier 단점 보완) (0) | 2022.06.13 |
---|---|
조회 대상 빈이 2개 이상인 경우 (@Primary, @Qualifier) (0) | 2022.06.13 |
Filter (0) | 2022.06.11 |
컴포넌트 스캔과 의존관계 주입 (@ComponentScan, @Autowired) (0) | 2022.06.10 |
@Configuration의 이해 - 스프링의 싱글톤 (0) | 2022.06.10 |