[Spring] 의존관계 자동 주입

GWANSU SHIN·2022년 7월 25일
0

spring

목록 보기
5/7

의존관계 주입 방법

1. 생성자 주입

  • 생성자를 통해서 의존관계 주입
  • 생성자 호출 시점에 1회만 호출되는 것이 보장됨
  • 불변, 필수 의존관계에 사용
@Component
public class OrderServiceImpl implements  OrderService{

    private final MemberRepository memberRepository;
    private final DiscountPolicy discountPolicy;

    @Autowired
    public OrderServiceImpl(MemberRepository memberRepository, DiscountPolicy discountPolicy) {
        this.memberRepository = memberRepository;
        this.discountPolicy = discountPolicy;
    }
}

생성자가 1개만 존재한다면 @Autowired를 생략해도 자동 주입

2. 수정자 주입 (setter 주입)

  • setter라 불리는 필드의 값을 변경하는 수정자 메서드를 통해서 의존관계를 주입하는 방법
  • 자바빈 프로퍼티 규약의 수정자 메서드 방식을 사용하는 방법
  • 선택, 변경 가능성이 있는 의존관계에 사용
@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;
	}
}

참고: @Autowired 의 기본 동작은 주입할 대상이 없으면 오류가 발생한다. 주입할 대상이 없어도 동작하게
하려면 @Autowired(required = false) 로 지정하면 된다.

참고: 자바빈 프로퍼티 규약은 필드의 값을 직접 변경하지 않고 getter, setter 메소드를 이용하여 값을 읽거나 수정하는 규칙

3. 필드 주입

  • 필드에 바로 주입하는 방법
  • 테스트하기 힘들다는 단점을 가짐
  • DI 프레임워크가 없으면 아무것도 할 수 없음
    • 주로 테스트 코드 또는 @Configuration 같은 곳에서 사용
@Component
public class OrderServiceImpl implements OrderService {
	@Autowired
	private MemberRepository memberRepository;
	
    @Autowired
	private DiscountPolicy discountPolicy;
}

4. 메소드 주입

  • 일반 메서드를 통해서 주입하는 방법
  • 한 번에 여러 필드를 주입할 수 있음
  • 잘 사용하지 않는 방법
@Component
public class OrderServiceImpl implements OrderService {
	private MemberRepository memberRepository;
	private DiscountPolicy discountPolicy;
 
	@Autowired
	public void init(MemberRepository memberRepository, DiscountPolicy discountPolicy) {
		this.memberRepository = memberRepository;
		this.discountPolicy = discountPolicy;
	}
}

생성자 주입을 선택하자

  • 생성자 주입 방식을 선택하는 이유는 여러가지가 있지만, 프레임워크에 의존하지 않고, 순수한 자바 언어의
    특징을 잘 살리는 방법이기도 하다.
  • 기본으로 생성자 주입을 사용하고, 필수 값이 아닌 경우에는 수정자 주입 방식을 옵션으로 부여하면 된다.
  • 생성자 주입과 수정자 주입을 동시에 사용할 수 있다.
  • 항상 생성자 주입을 선택해라! 그리고 가끔 옵션이 필요하면 수정자 주입을 선택해라. 필드 주입은 사용하지
    않는게 좋다.

옵션 처리

  • @Autowired(required=false) : 자동 주입할 대상이 없으면 수정자 메서드 자체가 호출 안됨
//호출 안됨
@Autowired(required = false)
public void setNoBean1(Member member) {
	System.out.println("setNoBean1 = " + member);
}
  • org.springframework.lang.@Nullable : 자동 주입할 대상이 없으면 null이 입력됨
//null 호출
@Autowired
public void setNoBean2(@Nullable Member member) {
	System.out.println("setNoBean2 = " + member);
}
  • Optional<> : 자동 주입할 대상이 없으면 Optional.empty 가 입력된다.
//Optional.empty 호출
@Autowired(required = false)
public void setNoBean3(Optional<Member> member) {
	System.out.println("setNoBean3 = " + member);
}
  • 출력 결과
setNoBean2 = null
setNoBean3 = Optional.empty

조회할 Bean이 2개 이상일 경우

  • @Autowired는 타입(type)으로 조회
    • 다음 코드와 유사하게 동작
    • ac.getBean(DiscountPolicy.class)
  • 타입으로 조회할 시 선택된 Bean이 2개 이상일 경우 문제 발생

기존 코드

@Autowired
private DiscountPolicy discountPolicy

1. @Autowired 필드 명 매칭

  1. 타입 매칭
  2. 타입 매칭의 결과가 2개 이상일 경우 필드 명, 파라미터 명으로 Bean 이름 매칭
@Autowired
private DiscountPolicy rateDiscountPolicy

2. Qualifier 사용

  1. @Qualifier끼리 매칭
  2. Bean 이름 매칭
  3. NoSuchBeanDefinitionException 예외 발생
@Component
@Qualifier("mainDiscountPolicy")
public class RateDiscountPolicy implements DiscountPolicy {}
  • Bean 이름을 변경하는 것이 아닌, 주입 시 추가적인 방법을 제공
  • 생성자 자동 주입, 수정자 자동 주입에 사용할 수 있음
  • @Bean을 이용한 직접 Bean 등록 시에도 사용할 수 있음
  • 주입 받을 때 모든 코드에 @Qualifier를 붙여주어야 함

3. @Primary 사용

@Autowired 시에 여러 개의 Bean이 매칭되면 @Primary가 우선권을 가짐

@Component
@Primary
public class RateDiscountPolicy implements DiscountPolicy {}

@Component
public class FixDiscountPolicy implements DiscountPolicy {}

우선순위 : @Qualifier > @Primary

Reference

[인프런] 스프링 핵심 원리 - 기본편

0개의 댓글