Spring Framework에서 의존성을 주입하는 방법은 3가지가 있다.
실무 코드에서 가장 많이 보이는 방식이다.
@Autowired 어노테이션을 사용하여 의존성을 주입한다.
public class InjectionTestController { @Autowired PersonService personService; }
같은 타입의 빈이 있는 경우에는 @Qualifier 혹은 @Resource 어노테이션을 통해 빈의 이름으로 가져와 의존성을 주입할 수 있다.
필드를 final로 선언할 수 없다.
빈을 생성한 후에 주입하려는 빈을 찾아 주입한다.
public class InjectionTestController { private PersonService personService; @Autowired public void setPersonService(PersonService personService) { this.personService = personService; } }
생성자 주입 방식은 Spring에서 권장하는 방식이다. 이유는 아래 설명!
public class InjectionTestController { private final PersonService personService; @Autowired InjectionTestController(PersonService personService) { this.personService = personService; } }
field injection 혹은 setter injection을 사용하면 인텔리제이에서는 아래와 같은 메시지를 보여준다. 생성자 주입 방식으로 의존성을 주입하라는 것이다.
이유는 final 선언 가능, 순환 참조 방지, 테스트 코드 작성 용이 3가지이다.
세 가지 방식중에 생성자 주입 방식만 유일하게 필드에 final로 선언할 수 있다. 이는 객체에 불변성(Immutability)을 보장한다는 말이므로 Thread-safe 를 보장한다는 뜻이다.
기본적으로 빈을 불변하도록(Immutable)해야 Thread-safe하게 어플리케이션을 운용할 수 있다.
순환 참조란 A클래스가 B클래스를 참조하고 다시 B클래스가 A클래스를 참조하는 경우를 말한다. 생성자 주입 방식을 사용하지 않는 경우에는 숨환 참조를 컴파일 시점에서 발견할 수가 없지만 생성자 주입 방식을 사용한다면 서버 자체가 구동이 되지 않는다.
이는 위에서 설명한 것처럼 각 방식마다 빈을 주입하는 순서가 다르기 때문에 차이가 나는 것이다.
즉, Bean이 생성된 이후에 변경되는 위험성이 다른 방식에 비해 줄어든다.
Mockito를 이용해 목킹한 후 테스트를 진행(JUNIT)해야 하는,혹은 서버를 구동시켜 bean을 모두 생성하여 테스트해야 하는 다른 방식과는 다르게 생성자 주입 방식은 순수 JAVA환경에서도 원하는 테스트 객체를 생성한 후 생성자에 넣어주고 테스트를 진행할 수 있어 테스트 코드 작성이 용이하다.
@RequiredArgsConstructor 어노테이션은 생성자 주입을 편리하게 도와주는 lombok 어노테이션이다.
final이나 @NotNull을 필드 앞에 붙이면 생성자를 자동으로 생성해준다.
의존성이 많아지는 경우 간결한 생성자 주입을 할 수 있도록 도와준다.
import lombok.RequiredArgsConstructor; @RequiredArgsConstructor public class InjectionTestController { private final PersonService personService; private final PersonRepository personRepository; }