
최근 RestTemplate에 대한 글을 작성 하면서, 아래의 코드를 작성 했었다.
@Configuration
class RestTemplateConfig {
@Bean
public RestTemplate restTemplate(RestTemplateBuilder restTemplateBuilder) {
return restTemplateBuilder
.setConnectTimeout(Duration.ofSeconds(5))
.setReadTimeout(Duration.ofSeconds(5))
.build();
}
}
위 코드는 RestTemplate 객체를 Bean으로 등록 하면서, Timeout 설정이 되어있는 객체를 반환하는 코드이다.
이 때 아래와 같은 궁금증이 생겼다.
@Bean 메서드의 매개변수인 RestTemplateBuilder를 어떻게 주입 받은거지?
내가 알고 있는 의존성 주입은 생성자 주입, setter 주입, 필드 주입등이 있는데 메서드 매개변수를 통한 주입이 따로 있는 것일까?
그리고 이 때 어떻게 Spring이 매개변수에 맞게 의존성을 주입하는지 알아보자.
Spring 공식 레퍼런스에서는 아래와 같은 예시 코드를 통해서 설명하고있다.
@Configuration
public class AppConfig {
@Bean
public TransferService transferService(AccountRepository accountRepository) {
return new TransferServiceImpl(accountRepository);
}
}
@Bean으로 어노테이션 된 메서드는 해당 Bean 객체를 생성하기 위해 필요한 의존성의 여러 매개변수를 가질 수 있다.
예를 들어, TransferService가 AccountRepository를 필요로 하는 경우, 위 예제와 같이 메서드 매개변수를 통해 그 의존성을 주입할 수 있다.
이 때 매개변수를 통해 의존 되는 AccountRepository는 반드시 Spring Container에 Bean으로 등록이 되어있어야 한다.
Spring에서는 이 매커니즘이 생성자 주입과 유사 하다고 설명하고있다.
어떤 점에서 Spring은 생성자 주입과 메서드 매개변수 주입이 비슷하다고 하는걸까?
@Service
public class SimpleMovieService {
private final MovieRepository movieRepository;
public SimpleMovieService(MovieRepository movieRepository) {
this.movieRepository = movieRepository;
}
}
위 소스 코드는 생성자 주입의 예시 코드이다.
생성자 주입은 생성자를 통해 의존 관계를 주입하는 방식이다.
생성자 주입은 생성자의 호출 시점에 1회 호출 되는 것이 보장되며, 주입 받은 객체가 변하지 않거나 반드시 객체의 주입이 필요한 경우 강제 하기 위해 사용된다.
이러한 생성자 주입과 메서드 매개변수 의존성 주입은 아래와 같은 점이 유사하다.
Bean 생성을 위해서 의존 객체가 필요하다는 전제가 @Bean 어노테이션을 통해서 드러나기에, 의존에 필요한 객체들을 드러낸 생성자 주입의 전제와 유사하다.
생성자 주입 예시 코드의 생성자를 보면, 본인 객체가 필요로 하는 의존 객체에 대해서 정확히 명시 되어있으며 이를 통해 의존성을 주입 받는다.
메서드 매개변수도 마찬가지로 본인이 필요로 하는 매개변수를 명시함으로써 위 생성자 주입과 유사하다고 하는 것이다.
이 둘은 유사한 전제를 지니고 있기에 결국 메서드 매개변수 주입 또한 Spring Container로부터 의존성을 주입 받는 것이다.
맨 위의 코드를 다시 봐보자.
@Configuration
class RestTemplateConfig {
@Bean
public RestTemplate restTemplate(RestTemplateBuilder restTemplateBuilder) {
return restTemplateBuilder
.setConnectTimeout(Duration.ofSeconds(5))
.setReadTimeout(Duration.ofSeconds(5))
.build();
}
}
RestTemplateBuilder는 분명 내가 별도로 Bean 등록을 해주지 않았는데, 어떻게 Spring Container에 Bean으로 등록 되어있어 주입 받을 수 있을까?
이는 전 글에서 설명했던 내용과 일치한다.
간단하게 요약하자면, spring-boot-strater-web 라이브러리를 의존 하여 사용할 경우 자동으로 필수적인 Bean들을 등록 시켜 주는데, 이 중 하나가 RestTemplateBuilder이다.
그리고 이 개념을 자동 구성(Auto Configuration)이라 한다.
이번에는 @Bean 어노테이션으로 등록 된 메서드의 매개변수를 통해서 의존성을 주입 받는 방식에 대해서 알아보았다.
DI에 대한 방식에 대해서 알아보면서, 단순히 새로운 의존성 주입 방식을 아는 것에 그치는걸 넘어 Spring 등의 프레임워크를 공부할 때 왜 이러한 개념을 만들었을까? 라는 생각을 하게 되었다.
의존성을 주입하는 다른 방식도 많지만, 메서드 매개변수를 통해 의존성을 주입하는 방식을 만든 이유가 뭘까?
이에 대해서 내 생각은 구성 클래스간 명확한 의존성을 관리할 수 있기 때문이라고 생각한다.
@Bean 메서드는 Spring Conatainer에 빈을 등록하는 메서드이다.
이 때 @Bean 메서드의 매개변수로 의존성을 주입 받으면, 의존성 관계가 코드에서 명확하게 알 수 있다.
@Bean
public TransferService transferService(AccountRepository accountRepository, NotificationService notificationService) {
return new TransferServiceImpl(accountRepository, notificationService);
}
위 예시 코드를 보면 AccountRepository, NotificationService을 매개변수로 작성하여 이를 통해 의존성을 주입 받고 있다.
이는 생성자 주입과 마찬가지로 별다른 @Autowired 같은 Spring의 구성품을 명시적으로 작성하지 않고, 의존성을 주입 받을 수 있게 코드의 의존 관계를 뚜렷하게 나타낼 수 있다고 생각한다.