스프링에서 한 클래스에 다른 클래스의 의존성을 부여하는 방법은 두 가지가 있다.
@Autowired 이용하기 (필드 주입)
`package wooteco.helloworld.core;
...
@Component
public class UserController {
@Autowired
private UserService userService;
@GetMapping("/users")
public String retrieveUsers() {
List<String> users = userService.findAll();
return "found it";
}
}`
@AutoWired 어노테이션을 통해 UserController에 UserService를 의존 시켰다.
생성자 주입 이용하기
`package wooteco.helloworld.core;
...
@Component
public class UserController {
private final UserService userService;
public UserController(UserService userService) {
this.userService = userService;
}
@GetMapping("/users")
public String retrieveUsers() {
List<String> users = userService.findAll();
return "found it";
}
}`
어노테이션을 쓰는 대신 final로 필드를 선언하고 생성자를 통해 주입받도록 했다.
IntelliJ에서는 필드 주입으로 구현할 경우 생성자 주입으로 변경할 것을 제안하도록 되어 있다. 즉 후자가 더 나은 구현이라는 건데, 왜 그런 것일까?
final로 선언해 불변성을 보장할 수 있다
당연하게도 final은 생성자 주입 시에만 사용할 수 있다.
테스트가 쉬워진다
생성자를 통해 의존관계의 클래스를 주입받기 때문에 테스트하기가 용이하다.
순환의존을 막을 수 있다
간단히 말하자면, 필드 주입을 이용할 시 순환의존을 막을 수 없다.
컴파일 시 에러가 잡히지 않고 실행시에 스택 오버플로우를 일으키기 때문에 골치아프게 된다.
생성자 주입을 이용할 시에는 순환 의존을 시도할 시 BeanCurrentlyInCreationException이 발생하며 구동되지 않는다.
참고 자료
- 생성자 주입을 @Autowired를 사용하는 필드 주입보다 권장하는 하는 이유
https://madplay.github.io/post/why-constructor-injection-is-better-than-field-injection
Comments powered by Disqus.