Baeldung - The Spring @Qualifier Annotation

sycho·2024년 3월 21일
0

Baeldung의 이 글을 정리 및 추가 정보를 넣은 글입니다.

1. Overview

  • 이번 글에서는 @Qualifier annotation이 뭔지, 어느 상황에서 어떤 용도로 쓰이는지를 알아보도록 하겠다.

  • 사실 이전 두 글들(1, 2)에서 중간 중간 언급을 했기 때문에 그걸 참고해도 좋다. 다만 거기서 안 다룬 내용을 여기서 조금 더 다룬다.

2. Autowire Need for Disambiguation

  • 이전에 implicit이 아닌 explicit하게 DI를 해주는 annotation으로 @Autowired에 대해서 알아봤었다.

  • 다만 이 annotation이 존재해도 spring이 무슨 bean을 주입해야 하는지 이해 못하는 상황이 있을 수 있다고 했다. @Autowired가 기본적으로 타입을 기반으로 주입하는데, 같은 타입의 bean이 여러개가 있는 경우에 무엇을 주입할지 모른다고 얘기했었다. 예를들어 밑과 같이 Formatter에 해당하는 bean이 2개 있고 이를 formatter에 주입 받는 FooService가 있는 경우가 있다.

@Component("fooFormatter")
public class FooFormatter implements Formatter {
 
    public String format() {
        return "foo";
    }
}

@Component("barFormatter")
public class BarFormatter implements Formatter {
 
    public String format() {
        return "bar";
    }
}

@Component
public class FooService {
     
    @Autowired
    private Formatter formatter;
}
  • 그리고 이전 두 글에서 여러번 봤지만, 이럴 때 @Qualifier을 사용한다.

3.@Qualifier Annotation

  • javadoc

  • 매우 간단한 annotation이다. 문장려에 해당하는 value를 받는다. 해당 값이 일치하는 bean을 autowire등을 통해 주입 받는다는 것을 spring에게 알릴 때 사용된다.

  • 이때 @Qualifier에 넣는 값이 bean의 무슨 값이랑 일치해야 하냐면

    • 그 bean의 class 이름의 camelcase 형태랑 일치하거나
    • 그 bean의 @Qualifier에 달려있는 이름이랑 일치해야 한다.
  • 앞의 예시의 경우 주입받는 측에서 다음과 같이 @Qualifier annotation을 쓰면 FooFormatter이라는 bean을 주입받게 된다. 해당 class의 camelcase 이름이 fooFormatter이기 때문.

public class FooService {
     
    @Autowired
    @Qualifier("fooFormatter")
    private Formatter formatter;
}
  • 아니면 밑과 같이 각 Formatter에 해당하는 class들의 @Component 밑에 다음과 같이 @Qualifier을 달아도 FooServicefooFormatter에 해당하는 bean을 주입받는다.
@Component
@Qualifier("fooFormatter")
public class FooFormatter implements Formatter {
    //...
}

@Component
@Qualifier("barFormatter")
public class BarFormatter implements Formatter {
    //...
}

4. @Qualifier vs. @Primary

@Primary

  • 사실 DI를 통해 주입해야 할 bean을 뭘로 할지 애매할 때 판별하는 annotation으로 @Primary라는 녀석도 존재한다.

  • 어떤 class가 특정 타입의 bean을 주입받아야 하는데 모든 규칙을 적용한 후에도 주입받을 수 있는 해당 타입의 bean이 여러개이면, @Primary가 달려있는 bean을 우선으로 주입받는다.

  • 예를 들어 밑과 같이 2개의 Employee bean을 만드는 @Configuration class를 봐보자.

@Configuration
public class Config {
 
    @Bean
    public Employee johnEmployee() {
        return new Employee("John");
    }
 
    @Bean
    @Primary
    public Employee tonyEmployee() {
        return new Employee("Tony");
    }
}
  • 이러면 어떤 class가 Employee라는 bean을 주입받으려 하고 특별히 추가 명시를 하지 않으면 tonyEmployee가 주입받게 된다.

  • 유의할건 앞에서 계속 언급했듯이, 다른 추가 명시가 없을 때 @Primary가 주입된다는 것이다. 이는 다른 말로 @Primary보다 우선순위가 높은 annotation을 사용시에 그걸 우선시해서 주입한다는 것이고, 그 중 하나가 @Qualifier이다.

  • @Qualifier이랑 @Primary가 혼용되면 기본 주입 bean이 @Primary이고, 때때로 @Qualifier을 활용해 다른 bean을 주입하는 것이라고 생각하면 된다.

  • 참고로 3번의 예제도 @Qualifier대신 @Primary를 통해 구현하는게 가능하다. 밑의 예시 참고.

@Component
@Primary
public class FooFormatter implements Formatter {
    //...
}

@Component
public class BarFormatter implements Formatter {
    //...
}

@Component
public class FooService {
     
    @Autowired
    private Formatter formatter;
}

5. @Qualifier vs. Autowiring by Name

  • 이전 두 글에서 언급을 했지만 이름을 기반으로 autowiring하는 것도 가능하다. 타입 기반 주입이 단 하나의 bean을 결정하지 않고 @Qualifier이 없으면 이름을 기반으로 주입한다고 했었다. 이때 이름은 class의 이름이 아닌 bean의 이름이라는 점 참고. 밑은 이를 활용해 @Qualifier 없이 fooFormatter 이름의 bean을 주입받는 것이다.
@Component
public class FooFormatter implements Formatter {
    //...
}

@Component
public class BarFormatter implements Formatter {
    //...
}

public class FooService {
     
    @Autowired
    private Formatter fooFormatter;
}
  • 다만 이 글에서 언급했듯 bean의 이름이랑 동일하게 attribute를 설정해야 한다는 것이 헷갈릴 수도 있기 때문에 상황에 따라 @Qualifier이랑 이름 기반 autowiring을 적절히 선택해서 쓰면 된다.
profile
안 흔하고 싶은 개발자. 관심 분야 : 임베디드/컴퓨터 시스템 및 아키텍처/웹/AI

0개의 댓글