[스프링] 생성자 주입

생성자 주입

특정 객체에 대한 의존 객체 주입(의존성 주입) 방법은 여러 가지가 있다. 그 중 생성자 주입(생성자 의존성 주입)은 객체의 하나 이상의 생성자를 이용해서 해당 객체가 필요로 하는 의존 객체 및 의존성을 제공하는 방식이다. 객체가 의존 객체를 인자로 받도록 생성자를 선언하면 컨테이너는 해당 객체를 초기화할 때(인스턴스화 할 때) 객체에 필요한 의존 객체를 전달한다.

생성자 주입의 방법 그 동작 방식은 다음과 같다.

  • 생성자에 @Autowired 어노테이션을 설정함으로써 빈 의존성 주입을 생성자 주입 방식으로 수행 가능하다.
  • 생성자의 파라미터로 주입할 의존 객체를 선언하고 의존 객체 필드 변수에 파라미터 변수를 할당한다.
  • 클래스의 객체가 생성될 때 자동으로 생성자가 호출되고 생성자의 인자로 스프링 컨테이너에 의해 생성된(애플리케이션 컨텍스트에 등록된) 컴포넌트 객체가 자동으로 전달되어 주입된다.
  • 객체가 생성될 때 생성자가 호출되므로 클래스의 객체 생성 시점에 의존 객체가 주입된다.
  • 생성자가 하나인 경우 어노테이션 지정은 필요 없다. 이를 암시적(implicit) 생성자 주입이라고 한다.
  • 구성 클래스에서도 생성자 주입 방식의 의존성 주입이 가능하다.
  • 의존 객체 필드 변수에 final 선언이 가능하므로 해당 객체에 대한 참조를 변경할 수 없게 만들 수 있다. 객체에 대한 의존 객체 변경이 불가능해진다.
  • 생성자 호출 시 주입할 의존 객체를 인자로 전달해야 하므로 인자로 전달된 주입 객체의 null 체크가 수행된다면 객체는 올바르게 인스턴스화 된 주입 객체를 갖게 된다. 이로써 의존 객체 참조 시 발생 가능한 null 참조 에러를 방지할 수 있다.
  • 생성자 호출 시 객체가 주입되므로(객체가 생성될 때 주입 객체가 인자로 전달됨) 객체와 주입 객체 간 의존 관계가 강제적이면서 필수적인 경우에 적합하다.


생성자 주입 방식의 특징에서 알 수 있듯이 생성자 주입이 권장되는 이유는 다음과 같다.

  • 생성자 주입을 사용하는 경우 의존성 주입 없이는 객체를 생성할 수 없으므로 반드시 의존성을 주입해야 하는 제약이 생기게 된다. 즉, 객체 주입 시점이 생성자 호출 시점이므로 객체를 주입받는 객체가 생성될 때 의존적인 객체가 주입된다. 따라서 객체 간 관계 설정 및 의존성 주입이 필수적인 경우 생성자 주입 사용이 필요하다. 생성자 주입 대신 수정자 주입을 사용하는 경우 의존성 주입 없이도 객체를 생성할 수 있으며 객체 생성 이후 수정자를 호출하여 의존 객체 및 의존성을 나중에 제공할 수 있다. 두 의존성 주입 방법의 차이는 의존성 주입 시점이다.
  • 애플리케이션 컨텍스트가 빈 객체 생성 및 관계 설정을 수행하고, 애플리케이션 실행 및 테스트 시 서로 의존 관계에 있는 객체들의 기능이 정상적으로 수행된다는 것만으로 의존성 검사가 충분할 수도 있지만 생성자에서 의존성 검사를 수행하는 생성자 주입은 객체 간 필수적인 의존성 검사를 수행하는 더 좋은 방법이다.


구성 클래스에서 생성자 주입

구성(configuration) 클래스 정의 시 @ComponentScan을 사용하여 등록할 컴포넌트 클래스가 위치한 패키지 위치를 설정하고 @Bean을 사용하여 빈 정의를 수행할 것이다. 이로써 컴포넌트 스캔과 빈 정의를 통해 애플리케이션 컨텍스트에 컴포넌트 및 빈을 등록할 수 있다. 등록된 빈 객체는 애플리케이션 컨텍스트로부터 직접 얻을 수 있다. @Component를 사용하여 컴포넌트로 등록할 클래스 또한 의존 객체를 가지는 경우 생성자 주입 방식으로 의존 객체를 주입할 수 있다. 이 경우 컴포넌트 스캔을 통한 컴포넌트 등록 시 해당 클래스의 생성자 주입이 일어난다.

스프링 4.3 부터는 구성 클래스에서도 생성자 주입 방식의 의존성 주입이 가능해졌다.


생성자 주입 시 주의점

생성자 주입 시 객체 인스턴스화 시점에 강제적인 의존 객체 주입이 일어나므로 생성자 호출 시 파라미터로 정의된 의존 객체의 빈이 컨텍스트에 등록되어 있지 않으면 NoSuchBeanDefinitionException 예외가 발생한다. 즉, 의존성 주입 대상 객체가 모두 준비되어 있어야 한다.

생성자 주입 방식에도 물론 단점이 존재한다.


참고

Comments