꼬물꼬물
의존관계 자동 주입 [옵션 처리, 생성자 주입] 본문
옵션 처리
주입할 스프링 빈이 없어도 동작해야할 때가 있다.
그런데 @Autowired만 사용하면 required 옵션 기본값이 true로 되어 잇어서 자동 주입 대상이 없으면 오류가 발생한다.
자동 주입 대상을 옵션으로 처리하는 방법
- @Autowired(reqiured=false): 자동 주입할 대상이 없으면 수정자 메서드 자체가 호출되지 않는다.
- org.springframework.lang.@Nullable: 자동 주입할 대상이 없으면 null이 입력된다.
- Optional<>: 자동 주입할 대상이 없으면 Optional.empty가 입력된다.
public class AutowiredTest {
@Test // bean 등록 테스트
void AutowiredOption(){
ApplicationContext ac = new AnnotationConfigApplicationContext(TestBean.class);
}
static class TestBean {
@Autowired(required = false)
public void setNoBean1(Member noBean1){
System.out.println("noBean1 = "+noBean1);
}
@Autowired
public void setNoBean2(@Nullable Member noBean2){
System.out.println("noBean2 = "+noBean2);
}
@Autowired
public void setNoBean3(Optional<Member> noBean3){
System.out.println("noBean3 = "+noBean3);
}
}
}
noBean1: required가 false일때, 의존 관계가 없다면 메서드 자체가 실행되지 않는다.
noBean2: @Nullable은 null 값을 삽입한다.
noBean3: Optional은 값이 없을 수도 있을 수도 있다. Optional.empty
Optional은 java8 문법
생성자 주입을 선택해라!
과거에는 수정자 주입과 필드 주입을 많이 사용했지만 최근에는 스프링을 포함한 DI 프레임워크 대부분이 생성자 주입을 권장한다!
🐤 불변
- 대부분의 의존관계 주입은 종료시점까지 변경할 일이 없다.
- 수정자 주입은 메서드를 public으로 열어둬야 한다. 이는 누군가 실수로 변경할 수 있고, 변경하면 안되는 메서드를 public으로 열어두는 것은 좋은 설계가 아니다.
- 생성자 주입은 객체 생성시 한번만 호출되므로 불변하게 설계할 수 있다.
🐤 누락
- 프레임워크 없이 순수한 자바 코드를 단위테스트하는 경우가 있다.
- 수정자의 경우
@Component
public class OrderServiceImpl implements OrderService{
// 생성자 주입
private MemberRepository memberRepository;
private DiscountPolicy discountPolicy;
@Autowired
public void setMemberRepository(MemberRepository memberRepository){
this.memberRepository = memberRepository;
}
@Autowired
public void setDiscountPolicy(DiscountPolicy discountPolicy){
this.discountPolicy = discountPolicy;
}
}
class OrderServiceImplTest {
@Test
void createOrder(){
OrderServiceImpl orderService = new OrderServiceImpl();
orderService.createOrder(1L, "itemA", 10000);
}
}
- NullPointerException이 난다.
- OrderServiceImpl에서는 memberRepository와 discountPolicy에 가짜 객체라도 값을 넣어줘야 한다.
- setXXX가 누락되었다.
- 생성자 주입을 사용할 경우, 컴파일 오류가 나기 때문에 미리 방지할 수 있다.
class OrderServiceImplTest {
@Test
void createOrder(){
MemoryMemberRepository memoryMemberRepository = new MemoryMemberRepository();
memoryMemberRepository.save(new Member(1L, "nameA", Grade.VIP));
OrderServiceImpl orderService = new OrderServiceImpl(memoryMemberRepository, new FixDiscountPolicy());
Order itemA = orderService.createOrder(1L, "itemA", 10000);
Assertions.assertThat(itemA.getDiscountPrice()).isEqualTo(1000);
}
}
🐤 final 키워드
- final: 생성할 때 정해지면 바뀌지 않는다.
- 초기값을 넣어주는것 아니면 생성자에서만 값을 세팅할 수 있다.
- 개발자가 실수로 생성자에서 누락했을 경우, 컴파일 오류로 컴파일 시점에 막아준다.
수정자 주입을 포함한 나머지 주입방식은 생성자 이후에 호출되므로, 필드에 final 키워드를 사용할 수 없다!
오직 생성자 주입 방식만 final 키워드를 사용할 수 있다.
✔️ 정리
- 생성자 주입 방식을 선택하는 이유는 여러가지가 있지만, 프레임워크에 의존하지 않고, 순수한 자바 언어의 특징을 잘 살리는 방법이기도 하다.
- 기본응로 생성자 주입을 사용하고, 필수값이 아닌 경우에는 수정자 주입 방식을 옵션을 부여하자. 생성자와 수정자 주입을 동시에 사용할 수 있다.
- 필드주입은 사용하지 않는 것이 좋다!
'스터디 > 스프링 핵심 원리 - 기본편' 카테고리의 다른 글
의존관계 자동 주입 [@Autowired 필드 명, @Qualifier, @Primary, 애노테이션 생성] (1) | 2022.09.30 |
---|---|
의존관계 자동 주입 [롬복과 최신 트랜드] (0) | 2022.09.30 |
의존관계 자동 주입 [다양한 의존관계 주입 방법] (0) | 2022.09.25 |
컴포넌트 스캔 [필터, 중복 등록과 충돌] (0) | 2022.09.22 |
컴포넌트 스캔 [의존관계 자동 주입, 탐색 위치와 기본 스캔 대상] (0) | 2022.09.19 |