Spring 스프링 핵심 원리 - 기본편 - 7. 의존관계 자동 주입
7. 의존관계 자동 주입
다양한 의존관계 주입 방법
- 생성자 주입
- 수정자 주입
- 필드 주입
- 일반 메서드 주입
생성자 주입을 권장
- 생성자를 통해서 의존 관계를 주입 받는 방법
- 특징
- 생성자 호출시점에 딱 1번만 호출되는 것이 보장
- 불변, 필수 의존관계에 사용
1
2
3
4
5
6
7
8
9
10
@Component
public class OrderServiceImpl implements OrderService {
private final MemberRepository memberRepository;
private final DiscountPolicy discountPolicy;
@Autowired //생성자가 1개만 있으면 생략 가능
public OrderServiceImpl(MemberRepository memberRepository, DiscountPolicy discountPolicy) {
this.memberRepository = memberRepository;
this.discountPolicy = discountPolicy;
}
}
불변
final 키워드
정리
- 생성자 주입 방식을 선택하는 이유는 여러가지가 있지만, 프레임워크에 의존하지 않고, 순수한 자바 언어의특징을 잘 살리는 방법이기도 하다.
- 기본으로 생성자 주입을 사용하고, 필수 값이 아닌 경우에는 수정자 주입 방식을 옵션으로 부여하면 된다. 생성자 주입과 수정자 주입을 동시에 사용할 수 있다.
- 항상 생성자 주입을 선택해라! 그리고 가끔 옵션이 필요하면 수정자 주입을 선택해라. 필드 주입은 사용하지 않는게 좋다.
롬복과 최신 트렌드
1
2
3
4
5
6
@Component
@RequiredArgsConstructor
public class OrderServiceImpl implements OrderService {
private final MemberRepository memberRepository;
private final DiscountPolicy discountPolicy;
}
- 롬복 라이브러리가 제공하는
@RequiredArgsConstructor
기능을 사용하면final
이 붙은 필드를 모아서 생성자를 자동으로 만들어준다.
조회 빈이 2개 이상 - 문제
@Autowired
는 타입(Type)으로 조회한다. → 타입으로 조회하면 선택된 빈이 2개 이상일 때 문제가 발생한다.
@Primary
, @Qualifier
활용
코드에서 자주 사용하는 메인 데이터베이스의 커넥션을 획득하는 스프링 빈이 있고, 코드에서 특별한 기능으로 가끔 사용하는 서브 데이터베이스의 커넥션을 획득하는 스프링 빈이 있다고 생각해보자.
- 메인 데이터베이스의 커넥션을 획득하는 스프링 빈은
@Primary
를 적용해서 조회하는 곳에서@Qualifier
지정 없이 편리하게 조회하고, 서브 데이터베이스 커넥션 빈을 획득할 때는@Qualifier
를 지정해서 명시적으로 획득 하는 방식으로 사용하면 코드를 깔끔하게 유지할 수 있다. - 물론 이때 메인 데이터베이스의 스프링 빈을 등록할 때
@Qualifier
를 지정해주는 것은 상관없다. @Primary
는 기본값 처럼 동작하는 것이고,@Qualifier
는 매우 상세하게 동작한다. 즉,@Qualifier
가 우선권이 높다.
조회한 빈이 모두 필요할 때, List, Map
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
public class AllBeanTest {
@Test
void findAllBean() {
ApplicationContext ac = new AnnotationConfigApplicationContext(AutoAppConfig.class, DiscountService.class);
DiscountService discountService = ac.getBean(DiscountService.class);
Member member = new Member(1L, "userA", Grade.VIP);
int discountPrice = discountService.discount(member, 10000, "fixDiscountPolicy");
assertThat(discountService).isInstanceOf(DiscountService.class);
assertThat(discountPrice).isEqualTo(1000);
}
static class DiscountService {
private final Map<String, DiscountPolicy> policyMap;
private final List<DiscountPolicy> policies;
public DiscountService(Map<String, DiscountPolicy> policyMap, List<DiscountPolicy> policies) {
this.policyMap = policyMap;
this.policies = policies;
System.out.println("policyMap = " + policyMap);
System.out.println("policies = " + policies);
}
public int discount(Member member, int price, String discountCode) {
DiscountPolicy discountPolicy = policyMap.get(discountCode);
System.out.println("discountCode = " + discountCode);
System.out.println("discountPolicy = " + discountPolicy);
return discountPolicy.discount(member, price);
}
}
}
정리
- 편리한 자동 기능을 기본으로 사용하자
- 직접 등록하는 기술 지원 객체는 수동 등록
- 다형성을 적극 활용하는 비즈니스 로직은 수동 등록을 고민해보자
References: 김영한 - [스프링 핵심 원리 - 기본편]
This post is licensed under CC BY 4.0 by the author.