웹 프로그래밍/[ Spring Boot ]

[ SpringBoot ] 02. Spring의 Autowiring과 Qualifer

kim.svadoz 2021. 10. 12. 16:53
반응형

Autowiring

IoC 컨테이너에 등록된 빈을 어떻게 꺼내서 사용할 것인가 ?

스프링에는 다양한 의존성 주입 방법이 있는데,

생성자로 직접 주입을 받아도 되지만 @Autowired를 사용하면 IoC 컨테이너에 들어있는 Bean을 주입받아서 사용할 수 있다.

스프링 컨테이너는 협력관계에 있는 빈들에 대해서 자동으로 관계를 주입한다.

ApplicationContext의 내용을 조사한 뒤에 Spring이 빈에 대해서 자동으로 다른 연관관계 빈에 대해서 의존성을 주입할 수 있도록 할 수 있다.

Autowire을 사용하면 다음과 같은 이점을 가진다.

  • 특정 프로퍼티나 생성자의 argument를 지정할 필요성을 크게 줄일 수 있다.
  • 클래스가 발전함에 따라서 구성의 업데이트를 쉽게 할 수 있다. 이 말은, 클래스에 종속성을 추가하는 경우 구성을 수정할 필요없이 해당 종속성이 자동으로 충족된다. 따라서 이 Autowiring은 개발 중에 매우 유용하다.

XML 기반의 환경설정을 사용한다면 autowire 속성으로 빈 정의에 대한 자동 연결 모드를 지정할 수 있다.

4가지 모드가 있고, 개발자는 각 빈에 대해서 autowiring을 지정하고 선택할 수 있다.

  • no
    • 기본값으로 Autowiring이 되지 않는다.
    • Bean references는 반드시 ref에 의해 정의되어야 하는 상태.
    • 명시적으로 공동 작업자를 지정하면 더 나은 제어와 명확성을 제공하므로 대규모 배포에는 기본 설정을 변경하지 않는 것이 좋다.
  • byName
    • 속성의 이름으로 자동 연결된다.
    • Spring은 자동으로 연결되어야 하는 속성과 이름이 같은 빈을 찾는다.
    • 예를 들어서 bean definition이 이름에 의해 autowire로 설정되고 master 속성을 포함 하는 경우(즉, setMaster(..) 메서드가 있는 경우) Spring은 이름이 지정된 bean definition의 master를 찾아서 속성을 설정하게된다.
  • byType
    • 속성의 타입의 bean이 컨테이너에 정확히 하나만 존재하는 경우에 속성이 자동으로 연결된다.
    • 둘 이상이 있다면 치명적인 예외가 발생하여 bean에 대해서 byType으로 autowiring할 수 없음을 나타낸다.
    • 일치 하는 빈이 없다면 아무 일도 일어 나지 않는다.(속성이 설정되지 않는다.)
  • constructor
    • byType과 유사하지만 생성자에 인수가 적용된다.
    • 컨테이너에 해당 생성자 유형의 빈이 정확히 하나 이상 없으면 치명적인 에러가 발생한다.

@Autowired

우리가 @Autowired로 의존성을 주입하는 경우 default로 byType의 모드로 동작된다. 만약 특정한 이름을 사용하고 싶으면 @Qualifer 어노테이션을 사용하면 된다.

Spring 4.3부터 어떠한 클래스에 생성자가 하나 뿐이고, 그 생성자가 주입받는 레퍼런스 변수들이 Bean으로 등록되어 있다면 그 Bean을 자동으로 주입하는 기능으로, @Autowired를 생략할 수 있다.

@Qualifer, @Primary

의존관계를 주입할 빈의 후보개 여러개라면 해결할 수 있는 세 가지 방법이 있다.

  1. @Autowried의 필드 매칭
    • Spring 5에서 추가된 바로는 매칭된 타입이 둘 이상일 경우에 Spring framwork는 적절한 후보를 찾기 위해서 필드명을 빈 이름으로 사용한다. (DefaultListBeanFacotory)
    • 의존성 주입을 받을 필드이름을 구현체의 이름으로 명시해서 찾는 방법이다.
    @Autowired
    private final OrderRepository orderRepository;
    • 이렇게 필드의 이름을 인터페이스가 아닌 실제 원하는 구현체의 이름을 적용시키는 것.
    • 하지만 추천하지 않고 @Primary@Qualifer를 적절히 사용하는 것이 권장된다.
  2. @Qualifer
    • @Qualifer는 여러개의 타입이 일치하는 bean객체가 있을 경우에 @Qualifer 어노테이션의 유무에 따라서 조건에 만족하는 객체를 주입하게 된다.
    • 선택되는 구현체들이나 사용하는 코드에 @Qualifer("찾는 이름")을 작성해서 주입받을 빈을 찾는다.
    @Component
    @Qualifer("mainDiscountPolicy")
    @Primary // 우선순위 사용예시 (rate가 아니라 fix를 먼저 찾게된다.)
    public class FixDiscountPolicy implements DiscountPolicy {
        private int discountFixAmount = 1000;
    
        @Override
        public int discount(Member meber, int price) {
            if (member.getGrade() == Grade.VIP) {
                return discountFixAmount;
            }
            return 0;
        }
    }
    @Component
    @Qualifer("subDiscountPolicy")
    public class RateDiscountPolicy implements DiscountPolicy {
        private int discountPercent = 10;
    
        @Override
        public int discount(Member member, int price) {
            if (member.getGrade() == Grade.VIP) {
                return price * discountPercent / 100;
            }
            return 0;
        }
    }
    // 활용 코드
    public class OrderServiceImpol implements OrderService {
        private final MemberRepository memberRepository;
        private final DiscountPolicy discountPolicy;
    
        public OrderServiceImpl(MemberRepository memberRepository, @Qualifer("mainDiscountPolicy") DiscountPolicy discountPolicy) {
            this.memberRepository = memberRepository;
            this.discountPolicy = discountPolicy;
        }
    }
  3. @Primary
    • @Primary 어노테이션으로 우선순위를 지정할 수 있다.
    • 같은 타입의 빈을 찾을 때 @Priamry가 붙은 빈을 우선적으로 찾게 된다.
    • 실무에서 많이 사용하는 방법!

참조 : https://velog.io/@neity16/Spring-%ED%95%B5%EC%8B%AC-%EC%9B%90%EB%A6%AC-%EA%B8%B0%EB%B3%B8%ED%8E%B8-8-Primary-Qualifier

Autowiring의 한계와 단점

Autowiring은 프로젝트 전체에서 일관되게 사용되어야 한다.

일관적으로 사용되지 않을 경우, 개발자가 빈 정의들을 연결하는 것에 혼란을 겪게 된다.

Autowiring에는 아래와 같은 한계와 단점이 존재한다.

  • propertyconstructor-arg으로 명시적 종속하는 것은 항상 Autowiring을 재정의한다. Primitive, String, Classes과 같은 단순 속성은 Autowiring할 수 없다. 의도적으로 설계된 것.
  • Autowiring은 명시적으로 주입하는 것보다 덜 정확하다. Spring이 예상치 못한 결과를 초래할 수 있는 모호한 경우를 대비해서 주의해야 한다.
  • 컨테이너 내의 여러 빈 정의는 자동 연결될 setter 메소드 뜨는 constructor-arg에 의해 지정된 유형과 일치할 수 있다. 배열, 컬렉션, 또는 Map 인스턴스의 경우 반드시 문제가 되는 것은 아니지만 단일 값을 기대하는 종속성의 경우 이 모호성이 임의로 해결되지 않는다. 사용 가능한 고유 빈 정의가 없으면 예외가 발생한다.

이를 위해 개발자에게는 다음과 같은 옵션이 주어진다.

  • 명시적 연결을 위해서 Autowiring을 포기하기
  • autowire-candidate 속성을 false로 설정하여 빈 정의에 대한 Autowiring을 방지하기
  • <bean/>primary 속성을 true로 설정하여 단일 빈정의를 기본으로 설정
  • annotation-based configuration을 기반으로 보다 세분화된 제어를 구현
반응형