NoTimeForDawdling

빈 주입 대상 설정하기(@Qualifier, @Primary) 본문

SpringBoot

빈 주입 대상 설정하기(@Qualifier, @Primary)

Room_Energy 2021. 2. 11. 16:01

Spring은 기본적으로 빈 주입을 설정을 자동으로 해줍니다. 하지만 동일한 타입을 가진 빈 객체가 두개 이상이라면 어떤 빈을 주입해야 할 지 알 수 없기 때문에 NoUniqueBeanDefinitionException을 발생시킵니다.

@Qualifier

@Qualifier 어노테이션은 주입할 빈 객체를 선택할 수 있도록 도와줍니다. 코드 예제를 통해 확인해 보겠습니다.

MainRestTemplateConfig.class

@Configuration
public class MainRestTemplateConfig {

    private static final int READ_TIME = 3000;
    private static final int CONNECT_TIME = 3000;

    @Bean(name = "mainRestTemplate") // 빈 이름 설정
    public RestTemplate restTemplate() {
        RestTemplateBuilder builder = new RestTemplateBuilder();
        return builder.setReadTimeout(Duration.ofMillis(READ_TIME))
                .setConnectTimeout(Duration.ofMillis(CONNECT_TIME))
                .build();
    }
}

CandidateRestTemplateConfig.class

@Configuration
public class CandidateRestTemplateConfig {

    private static final int READ_TIME = 10000;
    private static final int CONNECT_TIME = 10000;

    @Bean(name = "candidateRestTemplate") // 빈 이름 설정
    public RestTemplate restTemplate() {
        RestTemplateBuilder builder = new RestTemplateBuilder();
        return builder.setReadTimeout(Duration.ofMillis(READ_TIME))
                .setConnectTimeout(Duration.ofMillis(CONNECT_TIME))
                .build();
    }
}

@Configuration

위 코드는 @Configuration 어노테이션을 사용해서 Bean을 생성했습니다. @Configuration에 대한 설명은 다음과 같습니다.

  • @Configuration 어노테이션은 해당 클래스가 1개 이상의 Bean을 생성하고 있음을 명시합니다.
  • 그렇기 때문에 @Bean 어노테이션을 사용하는 클래스의 경우 반드시 @Configuration을 붙여줘야 합니다.
  • @Bean으로 정의된 메서드들은 Spring Container가 런타임에 해당 Bean을 정의합니다.

언제 사용하나?

  • 개발자가 직접 제어가 불가능한 라이브러를 활용할 때
  • 초기에 설정을 하기 위해 활용할 때

빈으로 등록된 RestTemplate 사용

@Service
public class RestTemplateService {

    private RestTemplate restTemplate;

    public RestTemplateService(RestTemplate restTemplate) {
        this.restTemplate = restTemplate;
    }

    public void call(){
        // doSomething
    }
}

위 서비스 코드는 다음과 같은 compile error를 보여줍니다.

 

Could not autowire. There is more than one bean of 'RestTemplate' type. Beans: candidateRestTemplate (CandidateRestTemplateConfig.java) mainRestTemplate (MainRestTemplateConfig.java)

 

해결책으로 @Qualifier 어노테이션으로 어떤 Bean을 사용할지 명시해주면 됩니다.

@Service
public class RestTemplateService {

    private RestTemplate restTemplate;

    public RestTemplateService(@Qualifier("mainRestTemplate") RestTemplate restTemplate) {
        this.restTemplate = restTemplate;
    }

    public void call(){
        // doSomething
    }
}

@Primary

-  @Primary어노테이션은 @Qualifier와 마찬가지로 종속성 주입과 관련된 모호성이 있을 때 주입할 빈을 결정하는데 사용할 수 있습니다.

-  @Primary어노테이션은 동일한 유형의 여러 Bean이 있는 경우 기본값을 정의합니다.

@Configuration
public class CandidateRestTemplateConfig {

    private static final int READ_TIME = 10000;
    private static final int CONNECT_TIME = 10000;

    @Primary
    @Bean(name = "candidateRestTemplate")
    public RestTemplate restTemplate() {
        RestTemplateBuilder builder = new RestTemplateBuilder();
        return builder.setReadTimeout(Duration.ofMillis(READ_TIME))
                .setConnectTimeout(Duration.ofMillis(CONNECT_TIME))
                .build();
    }
}