*이 글은 개인적인 공부/기록 목적으로 올립니다.
부족하다고 느껴질 수 있는 글이니 양해 부탁드립니다.*
참고 영상/저작권
스프링 핵심 원리 - 기본편 - 인프런 | 강의
스프링 입문자가 예제를 만들어가면서 스프링의 핵심 원리를 이해하고, 스프링 기본기를 확실히 다질 수 있습니다., - 강의 소개 | 인프런
www.inflearn.com
■ 롬복과 최신 트렌드
필드 주입처럼 좀 편리하게 사용하는 방법은 없을까?
- 롬복 라이브러리가 제공하는 @RequiredArgsConstructor 기능을 사용하면
final이 붙은 필드를 모아서 생성자를 자동으로 만들어준다.
(다음 코드에는 보이지 않지만 실제 호출 가능하다.)
@Component
@RequiredArgsConstructor
public class OrderServiceImpl implements OrderService {
private final MemberRepository memberRepository;
private final DiscountPolicy discountPolicy;
}
최근에는 생성자를 딱 1개 두고, @Autowired를 생략하는 방법을 주로 사용한다.
여기에 Lombok 라이브러리의 @RequiredArgsConstructor
함께 사용하면 기능은 다 제공하면서, 코드는 깔끔하게 사용할 수 있다.
조회 빈이 2개 이상일 때
@Component
public class FixDiscountPolicy implements DiscountPolicy {}
@Component
public class RateDiscountPolicy implements DiscountPolicy {}
public class Client {
@Autowired
private DiscountPolicy discountPolicy;
}
- DiscountPolicy 의 하위 타입 2개를 모두 스프링 빈으로 선언하면
NoUniqueBeanDefinitionException 오류가 발생한다.
NoUniqueBeanDefinitionException: No qualifying bean of type
'hello.core.discount.DiscountPolicy' available: expected single matching bean
but found 2: fixDiscountPolicy,rateDiscountPolicy
@Autowired 필드 명 매칭
- 타입 매칭을 시도하고, 이때 여러 빈이 있으면 필드 이름, 파라미터 이름으로 빈 이름을 추가 매칭한다.
@Autowired
private DiscountPolicy rateDiscountPolicy
@Qualifier
- 추가 구분자를 붙여주는 방법이다.
- 주입시 추가적인 방법을 제공하는 것이지 빈 이름을 변경하는 것은 아니다.
- @Qualifier 로 주입할 때 @Qualifier("mainDiscountPolicy") 를 못찾으면
mainDiscountPolicy라는 이름의 스프링 빈을 추가로 찾는다. - @Qualifier 끼리 매칭
- 빈 이름 매칭
- NoSuchBeanDefinitionException 예외 발생
@Primary
- 우선 순위를 정하는 방법이다.
- @Autowired할 때 여러 빈이 매칭되면 @Primary 붙은 빈이 우선권을 가진다.
스프링은 자동보다 수동이, 넓은 선택권 보다는 좁은 선택권이 우선 순위가 높다.
@Primary 는 기본값처럼 동작하지만 @Qualifier는 매우 상세하게 동작하는
기능이므로 @Qualifier가 우선권이 높다.
■ 롬복과 최신 트렌드
- @Qualifier("mainDiscountPolicy") 로 쓰면 String이므로 컴파일 할 떄 타입 체크가 안된다.
// 애너테이션을 직접 만든다.
@Target({ElementType.FIELD, ElementType.METHOD,
ElementType.PARAMETER,ElementType.TYPE, ElementType.ANNOTATION_TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Qualifier("mainDiscountPolicy")
public @interface MainDiscountPolicy
@Component
@MainDiscountPolicy
public class RateDiscountPolicy implements DiscountPolicy {}
조회한 빈이 모두 필요할 때
- 의도적으로 정말 해당 타입의 스프링 빈이 다 필요한 경우도 있다.
(예를 들어서 할인 서비스를 제공하는데, 클라이언트가 할인의 종류(rate, fix)를 선택할 수 있다면...)
public class DiscountService {
private final Map<String, DiscountPolicy> policyMap;
private final List<DiscountPolicy> policyList;
// 빈을 등록할 때 맵과 리스트를 주입받는다.
@Autowired
public DiscountService (
Map<String, DiscountPolicy> policyMap,
List<DiscountPolicy> policyList) {
this.policyMap = policyMap;
this.policyList = policyList;
}
}
- Map<String, DiscountPolicy> : map의 키에 스프링 빈의 이름을 넣어주고,
그 값으로 DiscountPolicy 타입으로 조회한 모든 스프링 빈을 담아준다. - List<DiscountPolicy> : DiscountPolicy 타입으로 조회한 모든 스프링 빈을 담아준다.
- 만약 해당하는 타입의 스프링 빈이 없으면, 빈 컬렉션이나 Map을 주입한다.
자동, 수동의 올바른 실무 운영 기준
- 편리한 자동 기능을 기본으로 사용하자
- 그러면 수동 빈 등록은 언제 사용하면 좋을까?
- 애플리케이션에 광범위하게 영향을 미치는 기술 지원 객체는 수동 빈으로 등록해서
설정 정보에 바로 나타나게 하는 것이 유지보수 하기 좋다.
- 애플리케이션에 광범위하게 영향을 미치는 기술 지원 객체는 수동 빈으로 등록해서
- 다형성을 적극 활용하는 비즈니스 로직은 수동 등록을 고민해보자.
(List, Map으로 조회한 빈이 모두 필요할 때)
'코딩공부 > 스프링' 카테고리의 다른 글
[스프링 핵심 원리 - 기본편] 8강 - 빈 스코프(1) (0) | 2023.04.14 |
---|---|
[스프링 핵심 원리 - 기본편] 7강 - 빈 생명주기 콜백 (0) | 2023.04.12 |
[스프링 핵심 원리 - 기본편] 5강 - 의존관계 자동 주입(1) (0) | 2023.04.10 |
[스프링 핵심 원리 - 기본편] 4강 - 컴포넌트 스캔 (0) | 2023.04.08 |
[스프링 핵심 원리 - 기본편] 3강 - 싱글톤 컨테이너 (0) | 2023.04.06 |