의존성주입(Dependencies Injection)

Daniel·2023년 5월 3일
0

개요

생성자 주입을 하며 final 키워드를 빼먹은 채 하루를 날린 나 자신...반성하며 이 포스트를 작성합니다.

스프링에서는 객체의 생성과 소멸 등에 대한 제어를 컨테이너가 관리하고 필요할 때 주입을 받아 사용한다.
본 포스트는 스프링 부트 기준으로 작성되었습니다. 스프링 과는 다른점이 있을 수 있습니다.

의존성 주입이 필요한 이유

자동차를 만든다고 상상해봅시다.
자동차에는 엔진, 타이어, 스티어링 휠과 같은 다양한 부품들이 존재하고 있습니다. 이러한 부품들은 Sping 애플리케이션의 빈과 같습니다.
위 부품들에는 엔진=연료, 타이어=공기, 스티어링 휠=운전자 와 같이 특정 리소스가 필요하다고 가정하고 의존성 주입을 사용하지 않으면 각 구성요를 수동으로 조립하고 필요한 리소스를 제공해야합니다.
또한 각 구성요소가 올바른 리소스에 연결되어 있는지 확인도 해줘야 합니다.

의존성 주입을 사용하게 되면 필요한 리소스를 각 구성요소에 주입 할 수 있습니다.
이 느슨한 결합은 코드를 더 모듈화하고 유연하며 이해하기 쉽게 만들어 줍니다.

좀 더 이해를 돕기위해 그림을 첨부해보았습니다.

DI 방식

1. 생성자 기반 주입

표준 Spring 프레임워크 기법 중 어떤 것이든 자유롭게 사용하여 빈과 주입된 종속성을 정의할 수 있습니다.
일반적으로 생성자 주입을 사용하여 종속성을 연결하고 @ComponentScan을 사용하여 빈을 찾는 것을 권장합니다.

public class SimpleMovieLister {
	// SimpleMovieLister는 MovieFinder에 의존한다.
	private final MovieFinder movieFinder;
	
	// Spring 컨테이너가 MovieFinder를 주입할 수 있는 생성자
	public SimpleMovieLister(MovieFinder movieFinder) {
		this.movieFinder = movieFinder;
	}
	
	// 주입된 MovieFinder를 실제로 사용하는 비즈니스 로직은 생략...
}

위 예제는 생성자 주입을 사용하여 필수 MovieFinder 빈을 가져오는 SImpleMovieLister 를 보여줍니다.
생성자 주입을 사용하면 MovieFinder 필드를 final 로 표시하여 나중에 변경 할 수 없음을 나타낼 수 있습니다.

1-1. 만약 생성자가 여러개라면?

빈에 생성자가 두 개 이상 있는 경우 Spring에서 사용할 생성자를 @Autowired로 표시해야 합니다:

2. setter 기반 주입

public class SimpleMovieLister {
	private MovieFinder movieFinder;
	
	public void setMovieFinder(MovieFinder movieFinder) {
		this.movieFinder = movieFinder;
	}
	
	// 비즈니스 로직 생략...
}

setter 기반 주입은 인수가 없는 생성자 또는 인수가 없는 static팩토리 메서드를 호출하여 Bean을 인스턴스화한 후 빈에서 setter 메서드를 호출하는 컨테이너에 의해 수행됩니다.

3. 필드 주입

public class SimpleMovieLister {
	@Autowired
	private MovieFinder movieFinder;
	
	// 비즈니스 로직 생략...
}

그래서 어떤 방법을 쓰는게 좋을까?

컨텍스트와 개발자의 기본 설정에 따라 다릅니다.

생성자 주입은 개체가 생성될 때 필요한 모든 종속성이 존재하도록 보장하기 때문에 일반적으로 모범 사례로 간주됩니다.
또한 클래스의 종속성을 이해하고 테스트 가능성을 개선하는 데 도움이 될 수 있는 종속성을 명시적으로 만듭니다.

Setter 주입은 설정할 수 있는 여러 종속성이 있거나 일부 종속성이 선택적일 때 유용합니다.

필드 주입은 가장 간단한 방법이지만 몇 가지 단점이 있습니다.
이는 클래스 간의 긴밀한 결합으로 이어져 테스트를 더 어렵게 만들 수 있습니다.
또한 명시적으로 선언되지 않았기 때문에 종속성을 식별하기가 더 어려워질 수 있습니다.

전반적으로 응용 프로그램의 특정 컨텍스트 및 요구 사항에 따라 사용할 주입 방법을 결정하는 것은 개발자의 몫입니다.

스프링 공식문서 중

생성자 기반 또는 세터 기반 DI?
생성자 기반 DI와 세터 기반 DI를 혼합할 수 있으므로 필수 종속성에 대해서는 생성자를 사용하고 선택적 종속성에 대해서는 세터 메서드 또는 구성 메서드를 사용하는 것이 좋습니다. setter 메서드에서 @Autowired 주석을 사용하여 속성을 필수 종속성으로 만들 수 있습니다. 그러나 프로그래밍 방식으로 인수를 검증하는 생성자 주입이 더 좋습니다.

Spring 팀은 일반적으로 생성자 주입을 옹호하는데, 이는 애플리케이션 구성 요소를 불변 객체로 구현하고 필수 종속성이 null. 또한 생성자 주입 구성 요소는 항상 완전히 초기화된 상태로 클라이언트(호출) 코드에 반환됩니다. 참고로 많은 수의 생성자 인수는 나쁜 코드 냄새입니다. 즉, 클래스에 너무 많은 책임이 있을 수 있으며 문제의 적절한 분리를 더 잘 해결하기 위해 리팩토링해야 합니다.

세터 주입은 기본적으로 클래스 내에서 합리적인 기본값을 할당할 수 있는 선택적 종속성에만 사용해야 합니다. 그렇지 않으면 코드가 종속성을 사용하는 모든 곳에서 null이 아닌 검사를 수행해야 합니다. setter 주입의 한 가지 이점은 setter 메서드가 해당 클래스의 개체를 나중에 재구성하거나 다시 주입할 수 있도록 만든다는 것입니다. 따라서 JMX MBeans를 통한 관리는 세터 주입에 대한 강력한 사용 사례입니다.

특정 클래스에 가장 적합한 DI 스타일을 사용하십시오. 때로는 소스가 없는 타사 클래스를 처리할 때 선택이 이루어집니다.
예를 들어 타사 클래스가 setter 메서드를 노출하지 않는 경우 생성자 주입이 유일하게 사용 가능한 DI 형식일 수 있습니다.

Reference

https://girawhale.tistory.com/113
https://docs.spring.io/spring-framework/docs/current/reference/html/core.html#beans-dependencies

profile
응애 나 애기 개발자

0개의 댓글