@Autowired field match, @Qualifier, @Primary
해당 내용은 '스프링 입문을 위한 자바 객체 지향의 원리와 이해'와 인프런 김영한님의 '스프링 핵심 원리 - 기본편' 강의를 참고하였습니다.
조회되는 빈이 2개 이상인 경우에는 어떻게 원하는 빈을 지정할까?
앞서 만들었던 클래스 구조에서 확인해보자.
우리는 FuelTank라는 인터페이스를 만들고,
ElectricBattery, GasolineOil 이라는 위의 인터페이스를 상속받은 클래스를 만들었다.
그런데 만약 우리가 위 2개의 클래스에 모두 @Componet
어노테이션을 달아줬다면 어떻게 될까?
이렇게 다 붙여보자.
ElectricBattery.java
@Component
public class ElectricBattery implements FuelTank {
...
GasolineOil.java
@Component
public class GasolineOil implements FuelTank{
...
자 이제 테스트를 돌려보자.
import static org.assertj.core.api.Assertions.assertThat;
public class AutoAppConfigTest {
@Test
void basicScan(){
AnnotationConfigApplicationContext ac = new AnnotationConfigApplicationContext(AutoApplicationConfig.class);
CarImpl carImpl = ac.getBean(CarImpl.class);
assertThat(carImpl).isInstanceOf(CarImpl.class);
}
}
그럼 이제 다음과 같이 에러를 만날 수 있을 것이다.
Caused by: org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type 'hello.core.carTest.tank.FuelTank' available: expected single matching bean but found 2: electricBattery,gasolineOil
(에러 메세지가 너무 친절하다...)
싱글 빈이 2개가 발견 되었다고 나온다.
이런 경우 스프링 빈을 수동등록 해도 해결은 되지만, 의존 관계 자동주입에서 해결하는 방법이 있다.
@Autowired 필드 명 매칭
@Autowired
는 타입 매칭을 시도하고, 이때 여러 빈이 존재하면 필드 이름으로 빈 이름을 추가 매칭한다.
아까 에러가 발생한 곳을 찾아가보자.
AutoApplicationConfig.java
@ComponentScan(
basePackages = "hello.core.carTest",
excludeFilters = {
@ComponentScan.Filter(type = FilterType.ANNOTATION, classes = Configuration.class) // 기존에 만든 다른 config 클래스가 빈으로 등록되는 것을 막기 위해서 제외시킨다.
})
public class AutoApplicationConfig {
}
여기서 에러가 발생하는데, 아마 위의 @ComponentScan
을 하면서 에러가 발생한 것 같다. 그러니 우리는 FuelTank가 생성자에 들어간 모든 곳에 우리가 사용하고자 하는 클래스 이름으로 바꿔주면 될 것이다.
이번엔 electricBattery
를 쓴다고 해보자. 그럼 다음과 같이 바꿔주면 될 것이다.
CarImpl.java
...
@Autowired
public CarImpl(FuelTank electricBattery) {
this.fuelTank = electricBattery;
}
...
FixServiceImpl.java
...
@Autowired
public FixServiceImpl(FuelTank electricBattery, Transmission transmission) {
this.fuelTank = electricBattery;
this.transmission = transmission;
}
...
자 이제 테스트를 돌려보면... 별 이슈 없이 잘 돌아갈 것이다.
@Autowired
의 필드 명 매칭은 우선적으로 타입 매칭을 한 뒤, 그 결과 여러 빈이 있는 경우에만 추가 작동하는 것이다.
@Qualifier
@Qualifier
는 추가 구분자를 붙여주는 방법이다.
이는 주입시에 추가적인 방법을 제공하는 것이지, 빈 이름을 변경하는 것은 아니다.
우선 각 컴포넌트에 다음과 같이 @Qualifier
어노테이션을 붙여준다.
ElectricBattery.java
@Component
@Qualifier("eletricBattery")
public class ElectricBattery implements FuelTank {
...
GasolineOil.java
@Component
@Qualifier("gasolineOil")
public class GasolineOil implements FuelTank{
...
자 그 다음에 사용되는 곳에 다음과 같이 적어준다.
CarImpl.java
...
@Autowired
public CarImpl(@Qualifier("eletricBattery") FuelTank fuelTank) {
this.fuelTank = fuelTank;
}
...
FixServiceImpl.java
...
@Autowired
public FixServiceImpl(@Qualifier("eletricBattery") FuelTank fuelTank, Transmission transmission) {
this.fuelTank = fuelTank;
this.transmission = transmission;
}
...
위의 자동 주입 받는 곳에서는 @Qualifier
가 있는 것을 확인하고, 해당 @Qualifier
의 이름에 맞는 것을 찾아서 주입시켜준다.
만약에, 등록하지 않은 @Qualifier
를 적으면 어떻게 될까?
그럼 등록하지 않은 @Qualifier
의 이름을 갖는 스프링 빈을 찾는다. (@Autowired
필드명 매칭 처럼!)
@Primary
@Primary
는 우선순위를 정하는 어노테이션 기법이다.
@Autowired
시에 여러 번 매칭되면, @Primary
를 갖는 빈이 우선권을 갖는다.
앞선 방법에 비교하면 훨씬 간단하다. (클래스에 어노테이션 하나만 붙이면 되니까..)
그렇기에, 뭔가 자주 사용하는 빈에는 @Primary
를, 자주 사용하지 않는 빈은 @Qualifier
를 사용해서 매칭하는 경우가 대부분이다.
(이 의미는, @Primary
와 @Qualifier
가 둘 다 존재하면, 매칭되는 @Qualifier
가 우선권이 더 높다는 의미이다.)
Author And Source
이 문제에 관하여(@Autowired field match, @Qualifier, @Primary), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://velog.io/@namkun/Autowired-field-match-Qualifier-Primary저자 귀속: 원작자 정보가 원작자 URL에 포함되어 있으며 저작권은 원작자 소유입니다.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)