Domain/Spring

[Spring] 의존성 주입의 방식 ( Autowired / Inject / Resource / Bean / DI / Constructor / Setter / Field / 순환참조 )

by Donghwan 2021. 9. 10.

스프링에서 DI를 적용하는 방식은 필드 주입 방식(Field Injection), 수정자 주입 방식(Setter Injection), 생성자 주입 방식(Constructor Injection)이 있습니다. 스프링 공식 문서에서는 생성자 주입 방식(Constructor Injection)과 수정자 주입 방식(Setter Injection)만 소개하고 있지만, 실제로 필드(Field) 방식도 가능합니다.

스프링에서는 필수적인 의존성에서는 생성자 주입 방식(Constructor Injection)을, 선택적인 의존성에서는 Setter Injection를 사용하라고 합니다.

이번 글에서는 주입방식 사용방법을 예시로 나타내고 왜 생성자(Constructor) 주입 방식을 사용해야 하는지에 대해 알아보도록 하겠습니다.

 

필드 주입 방식(Field Injection)

@Component
public class Sample {
    @Autowired
    private InjectSample injectSample;
}

필드 주입 방식을 이용하면 코드가 간결해져서 과거에 상당히 많이 이용되었던 주입 방법입니다. 하지만 필드 주입은 외부에서 변경이 불가능하다는 단점이 있습니다. 이러한 단점은 테스트가 어렵도록 하는 원인입니다. 또, 반드시 DI Framework가 존재해야 적용할 수 있습니다.

 

수정자 주입 방식(Setter Injection)

@Component
public class Sample {
    private InjectSample injectSample;

    @Autowired
    public void setInjectSample(InjectSample injectSample) {
        this.injectSample = injectSample;
    }
}

선택적인 의존성인 경우에 사용합니다. 런타임에 주입받는 객체가 변경될 가능성이 있는 경우에 사용합니다. 런타임에 체크하기 때문에 NPE이 발생할 가능성이 있기 때문에 사용에 주의해야 합니다. 주입이 필요한 객체가 주입이 되지 않아도 얼마든지 객체를 생성할 수 있다는 것이 문제입니다.

 

생성자 주입 방식(Constructor Injection)

@Component
public class Sample {
    private final InjectSample injectSample;
    
    @Autowired
    public Sample(InjectSample injectSample) {
        this.injectSample = injectSample;
    }
}

 

스프링에서는 필수적인 의존성인 경우에 생성자 주입 방식(Constructor Injection)을 추천하고 있습니다. 아래에서 그 이유를 살펴보겠습니다. 단일 생성자의 경우 @Autowired를 붙이지 않아도 자동으로 제공해주고 있습니다.

장점

1. 안정성

필수적인 의존성이 없다면 인스턴스를 생성할 수 없도록 강제하고 있습니다. 그리고 객체 생성 시 1회 호출되는 것이 보장됩니다. 최초 1회 호출이 보장되기 때문에 final 키워드를 사용할 수 있습니다. 따라서 불변성이 보장이 되고 NPE을 방지할 수 있습니다.

순환참조 상황에서 수정자 주입 방식(Setter Injection)과 필드 주입 방식(Field Injection)은 JVM의 동적 클래스 로딩에 의해 런타임 단계에서 StackOverFlow가 발생되어 오류를 야기할 수 있지만 생성자 주입 방식은(Constructor Injection)은 SpringBoot가 시작될 때 발견이 가능하기 때문에 안정성에서 유리하다고 할 수 있습니다.

필드 주입 방식(Field Injection)과 수정자 주입 방식(Setter Injection)
생성자 주입 방식(Constructor Injection)

 

2. Testable한 환경

DI 컨테이너에서 관리되는 클래스는 특정 컨테이너에 의존하지 않아야 합니다. 하지만 필드 주입 방식(Field Injection)을 사용하는 경우 DI Framework에 의존적이기 때문에 Spring이 아니면 해당 필드에 Injection을 할 수 있는 방법이 없습니다. 즉, Spring DI 컨테이너 밖에서 작동할 수 없는 코드를 만듭니다.


참고자료

728x90
반응형

댓글