의존성 주입(Dependency Injection)의 의미를 알아보고 Spring Boot로 의존성 주입을 해보겠습니다.
Spring Dependency Injection이란, 각 객체 간 의존관계를 스프링 컨테이너가 개발자가 정의한 Bean 등록 정보를 바탕으로 자동으로 주입해주는 기능이다.
일반적인 다양한 기존 스프링 프로젝트를 보면, Controller에서 Service나 Repository 객체를 사용 시, new 키워드를 통해 컨트롤러에서 객체를 직접 생성하여 사용하지 않고 의존성 주입을 통해 스프링 컨테이너에 생성된 객체를 받아 사용하고 있는 것을 볼 수 있다.
@Component, @Service, @Repository, @Controller 등의 어노테이션이 붙은 클래스들은 스프링 실행 시 스캔을 통해 개발자가 정의한 의존성 정보를 자동으로 bean 설정 정보에 등록을 하게 되어 의존성 주입이 동작하게 한다.
이를 통해 객체간 결합도를 낮추고, 코드의 양을 줄여주고, 테스트를 용이하게 하여, 개발 및 유지보수를 더 쉽게 하게 하는 장점이 있다.
스프링에서 의존성을 주입하는 방법은 아래와 같이 3가지 방법이 있다.
@Controller
public class TestController {
@Autowired
TestService testService;
}
가장 코드가 단순하지만 아래와 같은 단점이 있어 추천되지 않는 방식이다.
- 프레임워크 의존적 : 스프링 DI 컨테이너에서만 동작, 외부에서 수정 불가, 테스트의 어려움
- final 선언 불가 : 객체 변경 가능
@Controller
public class TestController {
private TestService testService;
@Autowired
public void setTestService(TestService testService) {
this.testService = testService;
}
}
수정자 주입 방식은 스프링 3.x대 버전에서 추천되었던 방식으로, 현재는 주입받는 객체가 변경될 가능성이 있을 경우에만 사용되는 방식이다.
@Controller
public class TestController {
private final TestService testService;
@Autowired // 생성자가 1개만 있을 경우 생략 가능
public TestController(TestService testService) {
this.testService = testService;
}
}
현재 스프링 프레임워크에서 가장 권장되는 방식이다. 간략히 아래와 같은 장점이 있다고 한다.
- 테스트 용이 : 프로엠워크 의존적이지 않아 순수 자바 등 외부 테스트 코드 작성 가능
- 객체 불변성 확보: final 선언 가능, 유지보수 용이성
- 순환 참조 에러가 발생할 경우 컴파일 시 판단 가능
생성자 주입 방식도 Lombok의 @RequiredArgsConstructor를 이용하면 코드를 아래와 같이 간결하게 작성할 수 있다.
@Controller
@RequiredArgsConstructor
public class TestController {
private final TestService testService;
}