의존관계 자동 주입이란?
좋은 객체지향 설계 중 DIP를 지키기 위해 필요한 의존관계 주입을 자동으로 시켜주는 기술입니다.
* DIP (의존관계 역전 원칙) : 프로그래머는 구체화에 의존하면 안되고, 추상화에 의존 해야합니다.
의존관계 자동 주입 어노테이션
스프링에서는 크게 2가지의 자동주입 어노테이션을 지원합니다.
1. @Resource - javax.annotation.Resource
여기에서는 @Autowired에 대해 자세히 설명할 것입니다.
2. @Autowired - org.springframework.beans.factory.annotation.Autowired
@Autowired 어노테이션을 사용하면 필요한 의존 객체의 타입에 해당하는 빈을 찾아 주입해줍니다.
빈 안에서 의존성 있는 타입을 찾아서 주입해주는 방식입니다. 마치 ac.getBean(DiscountPolicy.class) 방식과 유사하다고 생각하면 될 것 같습니다.
만일 타입이 없다면 Null값이 되어 NullTypeException이 발생합니다.
의존관계 자동 주입 방법
1. 생성자 주입 - Constructor injection
2. 수정자 주입 - getter/setter injection
3. 필드 주입 - field injection
의존관계 객체 선택
1. @Autowired 기본 매칭 원리
만일 타입에 해당하는 빈이 여러개가 있다면 NoUniqueBeanDefinitionException이 발생합니다. 즉, 1개 유니크한 빈이 정의되지 않고 2개 이상의 객체가 나와서 오류가 발생함을 의미합니다.
2. @Autowired 필드 명 매칭 원리 이용
의존 객체의 타입에 해당하는 빈이 여러개가 있다면, 필드 이름 혹은 파라미터 이름으로 추가 매칭합니다.
public OrderServiceImpl(memberRepository memberRepository, DiscountPolicy discountPolicy) {
this.memberRepository = memberRepository;
this.discountPolicy = discountPolicy;
}
// rateDiscountPolicy라고 빈 이름을 다르게 설정하면 각각 나눠서 의존관계를 설정해줍니다.
public OrderServiceImpl(memberRepository memberRepository, DiscountPolicy rateDiscountPolicy) {
this.memberRepository = memberRepository;
this.discountPolicy = rateDiscountPolicy;
}
3. @Qualifier 의존관계 객체 선택
의존관계를 주입하려는 객체를 직접 선택하여 주입하는 방법입니다.
@Autowired에서 @Qualifier("~~")를 먼저 찾은 후에 없다면 ""안에 문자열 이름으로 된 빈을 추가로 찾습니다.
// 1. 의존관계 주입 코드에 @Qualifier를 사용하고 이름을 등록합니다.
// 컴포넌트 스캔을 활용한 설정정보 주입이기 때문에 이렇게 바로 class에 쓸 수 있습니다.
// 빈 이름을 직접 설정하는 것은 아닙니다.
@Component
@Qualifier("fixDiscountPolicy")
public class FixDiscountPolicy implements DiscountPolicy
@Component
@Qualifier("mainDiscountPolicy")
public class RateDiscountPolicy implements DiscountPolicy
// 직접 빈을 수동 등록할 때 @Qualifier 사용 코드입니다.
@Bean
@Qualifier("mainDiscountPolicy")
public DiscountPolicy DiscountPolicy() {
return new rateDiscountPolicy();
}
// 2. 이후 @Autowired 적용된 코드에 적용합니다
// 지금과 같은 경우는 생성자 주입 방식이므로 파라미터 타입 앞에 명시하였습니다.
@Autowired
public OrderServiceImpl(memberRepository memberRepository, @Qualifier("mainDiscountPolicy") DiscountPolicy discountPolicy) {
this.memberRepository = memberRepository;
this.discountPolicy = discountPolicy;
}
4. @Primary 의존관계 우선권 부여
1번 방식에서 여러개의 빈이 존재할 때 @Primary가 붙은 객체가 우선순위가 되어 주입하는 방법입니다.
// @primary만을 붙이면 이후 생성자, 수정자 코드는 수정하지 않아도 동작합니다.
@Component
@Primary
public class RateDiscountPolicy implements DiscountPolicy
5. 어노테이션 직접 만들기
2번 방식에서 좀 더 발전된 방식으로, 컴파일 시에 타입 체크가 안되는 단점을 보완한 방법입니다.
// 1. mainDiscountPolicy를 사용할 어노테이션을 직접 만듭니다.
@Target({ElementType.FIELD, ElementType.METHOD, ElementType.PARAMETER, ElementType.TYPE, ElementType.ANNOTATION_TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Qualifier("mainDiscountPolicy")
public @interface mainDiscountPolicy {
}
// 2. 만든 @mainDiscountPolicy 어노테이션을 파라미터 타입 옆에 사용합니다.
@Autowired
public OrderServiceImpl(memberRepository memberRepository, @mainDiscountPolicy DiscountPolicy discountPolicy) {
this.memberRepository = memberRepository;
this.discountPolicy = discountPolicy;
}
의존관계 객체들이 모두 필요할 때
만일 위와 같이 선택하여 주입하는 것이 아니라 모두가 의존관계가 주입되는 것을 원할 때,
List 혹은 Map을 사용하면 됩니다.
자세한 코드는 github에 올라와있습니다.
'Backend > Spring Basic' 카테고리의 다른 글
[Spring Basic] 스프링의 본질, 다형성에 대해 (0) | 2022.08.17 |
---|---|
[Spring Web] DTO (2) | 2022.08.10 |
[Spring Basic] 빈 스코프 (0) | 2022.08.04 |
[Spring Basic] 빈 생명주기 콜백 (0) | 2022.08.01 |
[Spring Web] lombok 라이브러리 (0) | 2022.07.28 |