Spring ‐ 의존관계 자동 주입 - dnwls16071/Backend_Study_TIL GitHub Wiki

📚 다양한 의존관계 자동 주입 방법

  • 생성자 주입 방법✅
  • 수정자 주입 방법(setter)
  • 필드 주입 방법

[ 생성자 주입 방법 ]

  • 생성자 호출 시점에 딱 1번만 호출되는 것이 보장된다.
  • 불변, 필수 의존관계에 사용한다.
public class OrderServiceImpl implements OrderService {

	private final MemberRepository memberRepository;
	private final DiscountPolicy discountPolicy;

        @Autowired // 생성자가 1개만 있는 상황이라면 @Autowired를 생략해도 자동 주입 된다.
	public OrderServiceImpl(MemberRepository memberRepository, DiscountPolicy discountPolicy) {
		this.memberRepository = memberRepository;
		this.discountPolicy = discountPolicy;
	}
        
        // ...
}

[ 수정자 주입 방법 ]

  • 선택, 변경 가능성이 있는 의존 관계에 사용한다.
  • 자바빈 프로퍼티 규약의 수정자 메서드 방식을 사용한다.
@Component
public class OrderServiceImpl implements OrderService {

	private MemberRepository memberRepository;
	private DiscountPolicy discountPolicy;

	@Autowired
	public void setMemberRepository(MemberRepository memberRepository) {
		this.memberRepository = memberRepository;
	}

	@Autowired
	public void setDiscountPolicy(DiscountPolicy discountPolicy) {
		this.discountPolicy = discountPolicy;
	}
}

[ 필드 주입 ]

  • 필드에 바로 주입하는 방법이다.
  • 코드가 간결하나 DI 프레임워크가 없다면 아무것도 할 수 없다.
@Component
public class OrderServiceImpl implements OrderService {

	@Autowired private MemberRepository memberRepository;
	@Autowired private DiscountPolicy discountPolicy;

        // ...
}
  • 결론 : 생성자 주입 방법을 선택하기
    • 이유1 : 대부분의 의존관계 주입은 한 번 일어나면 애플리케이션 종료 시점까지 의존관계를 변경할 일이 없다. 오히려 대부분의 의존관계는 애플리케이션 종료 전까지 변하면 안 된다.
    • 이유2 : 수정자 주입을 사용하면 결국 public으로 열어두어야 하는데 이렇게 열어두게 되면 누군가 실수로 변경할 수 있기 때문에 좋은 설계가 아니다.
    • 이유3 : 생성자 주입은 객체를 생성할 때, 딱 1번만 호출되므로 이후에 호출되는 일이 없다. 따라서 불변하게 설계할 수 있다.

📚 조회되는 빈이 2개 이상인 경우 해결 방법 - @Autowired 필드명, @Qualifier, @Primary

  • 조회되는 빈이 2개 이상인 경우 NoUniqueBeanDefinitionException 예외가 발생한다.
  • @Autowired 필드명 매칭
  • @Qualifier
  • @Primary

[ @Autowired 필드명 매칭 ]

@Autowired
private DiscountPolicy discountPolicy;
@Autowired
private DiscountPolicy rateDiscountPolicy; // 특정 빈 이름으로 변경

[ @Qualifier ]

  • 추가 구분자를 붙여주는 방법이다.
@Component
@Qualifier("mainDiscountPolicy")
public class RateDiscountPolicy implements DiscountPolicy {}
@Component
@Qualifier("fixDiscountPolicy")
public class FixDiscountPolicy implements DiscountPolicy {}

[ @Primary ]

  • 우선순위를 정하는 방법이다.
@Component
@Primary
public class RateDiscountPolicy implements DiscountPolicy {}
@Component
public class FixDiscountPolicy implements DiscountPolicy {}

📚 어노테이션 커스텀 방법

// @Qualifier 어노테이션 내용에 붙은 어노테이션을 사용하면서 이름 부여
@Target({ElementType.FIELD, ElementType.METHOD, ElementType.PARAMETER, ElementType.TYPE, ElementType.ANNOTATION_TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
public @interface Qualifier {

	String value() default "";

}
@Target({ElementType.FIELD, ElementType.METHOD, ElementType.PARAMETER, ElementType.TYPE, ElementType.ANNOTATION_TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
@Qualifier("mainDiscountPolicy")
public @interface MainDiscountPolicy {
}