개발놀이터
스프링 @Autowired, @Component, @Qualifier, @Primary 본문
*@Autowired
스프링 빈의 의존관계를 자동으로 주입해주는 어노테이션이다. @Component 어노테이션으로 컴포넌트 스캔으로 등록된 클래스에서만 사용이 가능 하다. 컴포넌트 스캔으로
등록되지 않은 클래스에서 Autowired만 선언하면 아무런 의미가 없다. 기존의 @Bean을 이용하여 스프링빈에 등록하고 의존관계를 주입하는 것보다 훨씬 편한 방법으로
의존관계를 주입할 수 있다. 객체지향언어가 가져야할 원리다섯가지 SOLID의 D에 해당하는 DIP에 부합하는 어노테이션이다.
*@Component
컴포넌트 스캔을 실행할 때 스캔 대상이다. 스프링은 @ComponentScan 어노테이션을 보면 @Component 가 붙어있는 클래스들을 쭉 돌아서 찾아내고 스프링빈으로 등록한다.
스프링 빈에 등록된 빈들은 싱글톤 패턴을 적용하여 하나만 생성한 후 호출이 될때마다 생성된 빈을 가져다 쓰는 식으로 돌아간다.
*@Autowired로 지정된 의존관계 주입(DI)에서 같은 프로퍼티인 빈이 여러개 존재할 때
조회 대상 빈이 2개 이상일 때 해결방법은 다음과 같다.
1. @Autowired 필드 명 매칭
2. @Qualifier -> @Qualifier끼리 매칭 -> 빈 이름 매칭
3. @Primary 사용
1. @Autowired 필드 명 매칭
@Autowired는 타입 매칭을 시도하고, 이때 여러 빈이 있으면 필드 이름, 파라미터 이름으로 빈 이름을 추가 매칭한다.
필드명이 정상 주입되는 것을 찾아서 자동으로 매칭시켜준다.
2. @Qualifier 사용
@Qualifier는 추가 구분자를 붙여주는 방법이다. 주입 시 추가적인 방법을 제공하는 것이지 빈 이름을 변경하는 것은 아니다.
어노테이션을 추가로 붙이는데 @Qualifier("mainDiscountPolicy")를 적고 생성자에서
@Autowired
public OrderServiceImpl(MemberRepository memberRepository,@Qualifier("mainDiscountPolicy") DiscountPolicy discountPolicy) {
this.memberRepository = memberRepository;
this.discountPolicy = discountPolicy;
}
이렇게 추가해주면 된다.
3. @Primary 사용
@Primary는 우선순위를 정하는 방법이다. @Autowired시에 여러 빈이 매칭되면 @Primary가 우선권을 가진다.
*조회한 빈이 모두 필요할 때, LIst, Map
의도적으로 해당 타입의 스프링 빈이 다 필요한 경우도 있다.
예를 들어서 할인 서비스를 제공하는데, 클라이언트가 할인 종류를 선택할 수 있다고 가정해보자, 스프링을 사용하면 소위 말하는 전략패턴을 매우 간단하게 구현할 수 있다.
package hello.core.autowired;
import hello.core.AutoAppConfig;
import hello.core.discount.DiscountPolicy;
import hello.core.member.Grade;
import hello.core.member.Member;
import org.assertj.core.api.Assertions;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import java.util.List;
import java.util.Map;
import static org.assertj.core.api.Assertions.*;
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);
int rateDiscountPrice = discountService.discount(member, 20000, "rateDiscountPolicy");
assertThat(rateDiscountPrice).isEqualTo(2000);
}
static class DiscountService {
private final Map<String, DiscountPolicy> policyMap;
private final List<DiscountPolicy> policies;
@Autowired
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);
return discountPolicy.discount(member, price);
}
}
}
'Spring > Spring' 카테고리의 다른 글
스프링 빈 스코프 (0) | 2021.08.16 |
---|---|
스프링 빈 생명주기 콜백 (0) | 2021.08.16 |
스프링빈 조회 (0) | 2021.08.13 |
DI와 스프링빈 (0) | 2021.08.13 |
Spring 테스트클래스 (0) | 2021.08.10 |