본문 바로가기
Spring

[spring] 의존관계 자동 주입 - 생성자 주입을 사용해야 되는 이유

by 개미가되고싶은사람 2024. 3. 24.

다양한 의존관계 주입 방법

크게 4가지가 있다.

  • 생성자 주입
  • 수정자 주입(setter주입)
  • 필드 주입
  • 일반 메소드 주입

 

생성자 주입

이 방법은 객체를 생성할 때 생성자를 통해 의존성을 주입하는 방식이다. 스프링이 클래스의 생성자를 분석하여 필요한 의존 객체를 자동으로 주입한다. 

  • 생성자 호출시점에 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를 생략해도 자동 주입된다. 생성자 주입과 수정자 주입을 동시에 사용할 수 있다.

 

수정자 주입(setter 주입)

 Setter 메서드를 통해 의존성을 주입하는 방식이다. 주로 선택 ,변경 가능성이 있는 의존 관계에 사용에 사용한다

@Component
public class OrderServiceImpl implements OrderService {

    private  MemberRepository memberRepository;
    private DisCountPolicy disCountPolicy;

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

    @Autowired
    public void setDisCountPolicy(DisCountPolicy disCountPolicy) {
        this.disCountPolicy = disCountPolicy;
    }


}

 

※ Autowired만 사용하면 required 옵션의 기본 값이 true로 되어 있어서 자동 주입이 안되면 오류가 발생한다.

required=false 자동 주입할 대상이 없으면 그냥 넘어가어 간다

 

필드 주입

주로 권장하지 않는 방법이다. 프레임워크가 없으면 테스트를 할 수가 없다.

단 사용하는 경우가 2가지 있다.

  1. 테스트 자바 파일에서
  2. 설정하는 Configuration이 있는 자바 파일에서 사용
@Component
public class OrderServiceImpl implements OrderService {
    
	@Autowired
	private MemberRepository memberRepository;
    
	@Autowired
	private DiscountPolicy discountPolicy;
}

 

메소드 주입

메소드 주입은 한 번에 여러 필드를 주입받을 수 있는 장점이 있지만, 일반적으로는 사용되지 않는다. 이유는 메소드 주입이 객체의 생성 시점에 의존성을 명확하게 나타내지 않기 때문이다. 일반적으로 생성자 주입이나 Setter 주입을 사용할 때, 객체가 생성될 때 모든 의존성이 명시적으로 주입되어 생성 시점에 객체의 완전성을 보장할 수 있다.

@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;
    }
}

그리고 메소드 주입은 일반적으로 객체가 생성되고 초기화 메소드를 이용하여 의존성을 주입 받기 때문에 유지보수나 다른 사람이 코드를 볼때 불편함을 야기할 수 있다

 

이러한 이유 때문에 생성자 주입을 사용하는 것이 좋다

 

생성자 주입을 선택해야 되는 이유

스프링을 포함한 DI 프레임워크 대부분이 생성자 주입을 권장한다.

그 이유는 다음과 같다.

불변

  • 대부분의 의존관계 주입은 한번 일어나면 애플케이션 종료시점까지 의존관계를 변경할 일이 없다. 오히려 대부분의 의존 관계는 애플리케이션 종료 전까지 변경하면 안된다.
  • 수정자 주입을 사용하면, setXxx 메소드를 public으로 만들어야 한다. 이때 다른 사람이 실수로 변경할 수 있고, 변경하면 안되는 메소드를 만드는 것은 좋은 설계 방법이 아니다.
  • 생성자 주입은 객체를 생성할 때 딱 1번만 호출되므로 이후에 호출되는 일이 없다. 따라서 불변으로 설계할 수 있다.

프레임워크 없이 순수 Java 코드를 단위 테스트하는 경우

프레임워크 없이 순수 Java 코드를 단위 테스트하는 경우 수정자 주입으로 인해 NullPointerException이 발생할 수 있는 반면에 생성자 주입은 컴파일 오류가 발생하기 때문에 디버그 처리가 훨씬 편리하다