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
의존관계를 주입할 빈의 후보개 여러개라면 해결할 수 있는 세 가지 방법이 있다.
@Autowried
의 필드 매칭- Spring 5에서 추가된 바로는 매칭된 타입이 둘 이상일 경우에 Spring framwork는 적절한 후보를 찾기 위해서 필드명을 빈 이름으로 사용한다. (
DefaultListBeanFacotory
) - 의존성 주입을 받을 필드이름을 구현체의 이름으로 명시해서 찾는 방법이다.
@Autowired private final OrderRepository orderRepository;
- 이렇게 필드의 이름을 인터페이스가 아닌 실제 원하는 구현체의 이름을 적용시키는 것.
- 하지만 추천하지 않고
@Primary
나@Qualifer
를 적절히 사용하는 것이 권장된다.
- Spring 5에서 추가된 바로는 매칭된 타입이 둘 이상일 경우에 Spring framwork는 적절한 후보를 찾기 위해서 필드명을 빈 이름으로 사용한다. (
@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; } }
@Primary
@Primary
어노테이션으로 우선순위를 지정할 수 있다.- 같은 타입의 빈을 찾을 때
@Priamry
가 붙은 빈을 우선적으로 찾게 된다. - 실무에서 많이 사용하는 방법!
Autowiring의 한계와 단점
Autowiring은 프로젝트 전체에서 일관되게 사용되어야 한다.
일관적으로 사용되지 않을 경우, 개발자가 빈 정의들을 연결하는 것에 혼란을 겪게 된다.
Autowiring에는 아래와 같은 한계와 단점이 존재한다.
property
및constructor-arg
으로 명시적 종속하는 것은 항상 Autowiring을 재정의한다.Primitive
,String
,Classes
과 같은 단순 속성은 Autowiring할 수 없다. 의도적으로 설계된 것.- Autowiring은 명시적으로 주입하는 것보다 덜 정확하다. Spring이 예상치 못한 결과를 초래할 수 있는 모호한 경우를 대비해서 주의해야 한다.
- 컨테이너 내의 여러 빈 정의는 자동 연결될
setter
메소드 뜨는constructor-arg
에 의해 지정된 유형과 일치할 수 있다. 배열, 컬렉션, 또는Map
인스턴스의 경우 반드시 문제가 되는 것은 아니지만 단일 값을 기대하는 종속성의 경우 이 모호성이 임의로 해결되지 않는다. 사용 가능한 고유 빈 정의가 없으면 예외가 발생한다.
이를 위해 개발자에게는 다음과 같은 옵션이 주어진다.
- 명시적 연결을 위해서 Autowiring을 포기하기
autowire-candidate
속성을false
로 설정하여 빈 정의에 대한 Autowiring을 방지하기<bean/>
의primary
속성을 true로 설정하여 단일 빈정의를 기본으로 설정- annotation-based configuration을 기반으로 보다 세분화된 제어를 구현
'웹 프로그래밍 > [ Spring Boot ]' 카테고리의 다른 글
[ SpringBoot ] 05. RestController가 뭐죠? (0) | 2021.10.12 |
---|---|
[ SpringBoot ] 04. Lombok 라이브러리 (0) | 2021.10.12 |
[ SpringBoot ] 03. Spring의 Bean Scope를 알아보자 (0) | 2021.10.12 |
[ SpringBoot ] 01. Spring Bean의 LifeCycle (0) | 2021.10.12 |
[ SpringBoot] 00. @SpringBootApplication Annotaion (0) | 2021.10.12 |