쌓고 쌓다

@Autowired 조회 빈이 2개 이상일때 해결 방법 본문

프로그래밍/spring

@Autowired 조회 빈이 2개 이상일때 해결 방법

승민아 2023. 7. 15. 14:21

OrderServiveImpl

@Component
public class OrderServiceImpl implements OrderService {

    private MemberRepository memberRepository;
    private DiscountPolicy discountPolicy;


    @Autowired
    public OrderServiceImpl(MemberRepository memberRepository, DiscountPolicy discountPolicy) {
        this.memberRepository = memberRepository;
        this.discountPolicy = discountPolicy;
    }

}

@Autowired는 타입으로 조회하기에 아래와 유사하다.

ac.getBean(DiscountPolicy.class);

DiscountPolicy 타입으로 조회시 자식 타입도 함께 조회되기에 FixDiscountPolicy, RateDiscountPolicy가 함께 조회된다.

빈이 2개이상 조회가 되어 생성자 @Autowired에서 문제가 발생한다.

 

여기서 하위 타입인 FixDiscount, RateDiscoun로 지정하여 스프링 빈을 가져올 수 있지만.

역할과 구현의 분리 DIP가 위반된다. 우리는 DiscountPolicy에 의존해야지 구현체인 FixDiscount, RateDiscount에 의존하면 안된다.

해결 방법 3가지를 알아보자.

 

RateDiscountPolicy를 주입하길 원한다고 가정한다.

1. 필드명 매칭

@Autowired 아래의 과정으로 매칭한다.

  1. 타입 매칭
  2. 타입 매칭시 2개 이상 빈이 나오면 필드 명, 파라미터 명으로 매칭

 

필드 명으로 해결

@Autowired
private DiscountPolicy rateDiscountPolicy;

/*
기존
@Autowired
private DiscountPolicy discountPolicy;
*/

 

파라미터 명으로 해결

@Autowired
public OrderServiceImpl(MemberRepository memberRepository, DiscountPolicy rateDiscountPolicy) {
	this.memberRepository = memberRepository;
    this.discountPolicy = rateDiscountPolicy;
}

DiscountPolicy로 타입 매칭을 시도했으나 2개이상 빈이 존재하므로

파라미터명인 rateDiscountPolicy와 일치하는 빈을 찾아 주입한다.

 

2.  @Qualifier

@Qualifier는 추가 구분자를 만드는것이지 빈 이름을 변경하는 방법이 아니다.

 

RateDiscountPolicy

@Component
@Qualifier("mainDiscountPolicy")
public class RateDiscountPolicy implements DiscountPolicy{ ... }

 

FixDiscountPolicy

@Component
@Qualifier("fixDiscountPolicy")
public class FixDiscountPolicy implements DiscountPolicy{ ... }

 

OrderServiceImpl

@Component
public class OrderServiceImpl implements OrderService {

    private MemberRepository memberRepository;
    private DiscountPolicy discountPolicy;

    @Autowired
    public OrderServiceImpl(MemberRepository memberRepository, @Qualifier("mainDiscountPolicy") DiscountPolicy discountPolicy) {
        this.memberRepository = memberRepository;
        this.discountPolicy = discountPolicy;
    }
}

주입시 @Qualifier에 등로간 추가 구분자 이름을 적어준다.

 

3.  @Primary

@Primary를 통해 우선순위를 지정할 수 있다.

@Autowired시 빈이 여러개 조회 될 경우 @Primary가 우선권을 가진다.

 

@Primary 적용

@Component
@Primary
public class RateDiscountPolicy implements DiscountPolicy{ ... }

@Component
public class FixDiscountPolicy implements DiscountPolicy{ ... }

 

@Autowired 주입

@Component
public class OrderServiceImpl implements OrderService {

    private MemberRepository memberRepository;
    private DiscountPolicy discountPolicy;

    @Autowired
    public OrderServiceImpl(MemberRepository memberRepository, DiscountPolicy discountPolicy) {
        this.memberRepository = memberRepository;
        this.discountPolicy = discountPolicy;
    }
}

DiscountPolicy 타입으로 여러개 빈이 조회되었지만 @Primary가 붙은 RateDiscountPolicy가 우선순위를 갖는다.

 

@Primary, @Qualifier 활용

자주 사용하는 메인 DB의 커넥션을 획득하는 스프링 빈은 @Primary로 @Qualifier 없이 편히 조회하고,

가끔 사용하는 서비 DB의 커넥션을 획득하는 스프링 빈은 @Qualifier를 통해 명시적으로 획득하게하면 코드가 깔끔.

 

@Priamry와 @Qualifier를 동시에 사용한다면 어떤것이 우선순위를 가질까?

@Priamry는 기본값처럼 동작하고 @Qualifier는 사용자가 세세하게 지정한다.

스프링은 자동보단 수동이, 넓은 범위보단 좁은 범위가 우선 순위가 더 높다.

=> @Qualifier가 우선순위이다.

 

 

 

 

 

 

 

Comments