Backend/Spring+Boot

Spring에서 권장되는 의존성 주입 방법

findmypiece 2021. 7. 23. 00:32
728x90

A클래스에서 B클래스의 메소드를 사용하려면 A클래스에서 B클래스를 인스턴스화 해서 사용해야 한다. 이 때 B를 A의 의존성이라고 하고 B의 인스턴스를 생성하는 것을 의존성을 주입한다고 표현한다.

 

이러한 연결을 위해 일반적으로 A클래스에서 코드상 new B() 를 통해 B의 의존성을 직접 주입해야 하지만 Spring 환경이라면 이러한 의존성성 주입을 Spring에서 담당해준다.

 

하지만 컨테이너에게 의존성을 주입해 달라는 액션을 취해야 하는데 그 방법은 아래와 같이 세 가지가 있다.

  1. 생성자 정의
  2. Setter 메소드 정의
  3. 필드에 @Autowired 지정

이 중 권장되는 방식은 생성자 정의 방식이다. 여러 이유가 있겠지만 개인적으로 많이 공감했던 내용 위주로 정리해본다.

 

Setter 메소드 정의 방식의 경우 기본적으로 코드양이 가장 많기 때문에 거의 사용되지 않는다. 하지만 그 외에도 이 방식을 사용할 경우 Setter 메소드로 의존성이 주입되지 않더라도 A클래스를 인스턴스화 하고 사용하는데 아무런 문제가 되지 않기 때문에 실제 의존성이 활용되는 런타임 시에나 NullPointerException 으로 의존성이 없다는 것을 인지할 수 있다. 즉, 정상적으로 빌드되고 구동되었다 하더라도 의존성 주입이 보장되지 않는다.

 

필드에 @Autowired를 지정하는 방식은 굉장히 간단하기 때문에 Spring 초기에 굉장히 많이 활용되었다. 하지만 쉽다는 것은 동시에 큰 단점이기도 하다. 쉽기 때문에 의존성이 지나치게 많이 사용될 수 있고 적절히 분리해서 리팩토링 해야 할 시기를 놓힐 수 있다. 또한 순환참조에 에러를 사전에 인지할 수 없다.

 

순환참조란 A클래스 a메소드에서 B클래스의 b메소드를 호출하는데 B클래스의 b메소드에서도 A클래스의 a메소드를 호출하고 있는 상황을 말한다. 결국 무한대로 호출반복하다가 StackOverflowError 를 발생시키면서 어플리케이션이 종료되는 상황이 발생하게 된다. 즉, Setter 메소드 정의 방식과 동일하게 정상적으로 빌드 되고 구동되었다 하더라도 순환참조에서 자유로울 수 없다.

 

생성자 정의 방식의 경우 위에서 말한 단점이 모두 보완된다. 의존성이 생성자의 인자로 존재하기 때문에 A클래스를 인스턴스 할 때 의존성 주입이 강제되고, 생성자 정의시 의존성이 너무 많지는 않은지 인지할 수 있으며 순환참조 상황이 존재할 경우 어플리케이션 구동이 실패한다. 부가적으로 생성자에 포함되는 필드는 final 키워드가 강제되기 때문에 의존성의 Immutable 이 보장된다.

 

이처럼 의존성을 주입할 때 생성자 정의 방식이 권장되는데 Junit 테스트 코드 작성시에는 이게 정상적으로 동작하지 않는다. 그 이유는 Junit의 경우 자체적으로 DI가 동작하고 생성자에 다른 의존성을 주입하려고 먼저 개입하기 때문이다. 이에 테스트 코드 작성시에는 별 수 없이 필드에 @Autowired 를 지정하는 방식을 사용해야 한다.

728x90

'Backend > Spring+Boot' 카테고리의 다른 글

Thymeleaf 훑어보기  (0) 2021.07.30
의존성 주입시 중복되는 타입에 대한 처리  (0) 2021.07.23
RestClient 구성시 고려사항  (0) 2021.07.20
UriComponentsBuilder  (0) 2021.07.19
@RunWith(SpringRunner.class)  (0) 2021.07.13