1.5 스프링의 IoC

  • 스프링의 핵심 → 애플리케이션 컨텍스트(빈 팩토리)

1.5.1 오브젝트 팩토리를 이용한 스프링 IoC

어플리케이션 컨텍스트와 설정정보

  • 빈(bean) : 스프링이 제어권을 가지고 직접 만들고 관계를 부여하는 오브젝트
    • 스프링 빈은 스프링 컨테이너가 생성과 관계설정, 사용 등을 제어해주는 제어의 역전이 적용된 오브젝트를 가리키는 말
  • 빈 팩토리(bean factory) : 빈의 생성과 관계 설정과 같은 제어를 담당하는 IoC 오브젝트
  • 애플리케이션 컨텍스트 : 별도의 정보를 참고해서 빈의 생성, 관계설정 등의 제어 작업 총괄. IoC엔진이라는 의미가 부각됨.
  • 애플리케이션은 컨텍스트와 설정 정보를 따라 만들어지고 구성됨.

DaoFactory를 사용하는 애플리케이션 컨텍스트

  • @Configuration
    • 애플리케이션 컨텍스트 또는 빈 팩토리가 사용할 설정정보 표시
  • @Bean
    • 오브젝트 생성을 담당하는 IoC용 메소드 표시

1.5.2 애플리케이션 컨텍스트의 동작 방식

  • 오브젝트 팩토리 - 스프링의 애플리케이션 컨텍스트 (=IoC 컨테이너, 빈 팩토리)
  • 애플리케이션 컨텍스트는 애플리케이션에서 IoC를 적용해서 관리할 모든 오브젝트에 대한 생성과 관계설정을 담당한다.
  • 애플리케이션 컨텍스트 사용시 장점
    • 클라이언트는 구체적인 팩토리 클래스를 알 필요가 없음.
      • 오브젝트 팩토리가 많아져도 이를 알아야 하거나 직접 사용할 필요가 없음.
    • 애플리케이션 컨텍스트는 종합 IoC 서비스를 제공
      • 오브젝트 생성과 다른 오브젝트와의 관계 설정 뿐만 아니라 다양한 기능 제공(오브젝트가 만들어지는 방식, 시점과 전략을 다르게 가져갈 수 있음.)
    • 애플리케이션 컨텍스는 빈을 검색하는 다양한 방법 제공

1.5.3 스프링 IoC의 용어 정리

  • 빈(bean) : 스프링이 IoC 방식으로 관리하는 오브젝트.
    • 스프링에서 사용하는 애플리케이션에서 만들어지는 모든 오브젝트가 다 빈은 아님.
  • 빈 팩토리(bean factory) : 스프링의 IoC를 담당하는 핵심 컨테이너를 가리킴.
    • 빈 동륵, 생성, 조회, 돌려주기 등의 빈 관리 기능 담당
  • 애플리케이션 컨텍스트(application context) : 빈 팩토리를 확장한 IoC 컨테이너.
    • 빈 팩토리의 빈 관리하는 기본 기능 + 스프링이 제공하는 부가 서비스
    • 빈 팩토리보다 애플리케이션 컨텍스트라는 이름을 더 많이 사용함.
  • 설정정보/설정 메타 정보(configuration metadata)
    • 애플리케이션 컨텍스트 또는 빈 팩토리가 IoC를 적용하기 위해 사용하는 메타정보
    • 스프링의 설정정보는 컨테이너에 어떤 기능을 세팅하거나 조정하는 경우에도 사용하지만, 그보다는 IoC 컨테이너에 의해 관리되는 애플리케이션 오브젝트를 생성하고 구성할 때 사용
  • 컨테이너(or IoC 컨테이너)
    • IoC 방식으로 빈을 관리한다는 의미에서 애플리케이션 컨텍스트나 빈 팩토리를 컨테이너 또는 IoC 컨테이너라고 함.
      • 컨테이너 → 애플리케이션 컨텍스트 / IoC 컨테이너 → 빈 팩토리 관점
  • 스프링 프레임워크 : IoC 컨테이너, 애플리케이션 컨텍스트를 포함해서 스프링이 제공하는 모든 기능을 통틀어 말할 때 주로 사용한다.

1.6 싱글톤 레지스트리와 오브젝트 스코프

  • 오브젝트의 동일성과 동등성
    • 동일성(identify) - 두 개의 오브젝트가 완전히 같은 동일한 오브젝트
      • 하나의 오브젝트만 존재. (두 개의 오브젝트 레퍼런스 변수)
    • 동등성(equality) - 동일한 정보를 담고 있는 오브젝트
      • 두 개의 각기 다른 오브젝트
    • 스프링은 여러 번 빈을 요청해도 매번 동일한 오브젝트를 돌려줌.

1.6.1 싱글톤 레지스트리로서의 애플리케이션 컨텍스트

  • 애플리케이션 컨텍스트는 싱글톤을 저장하고 관리하는 싱글톤 레지스트리(singleton registry)이기도 함.

서버 애플리케이션과 싱글톤

  • 스프링이 싱글톤으로 빈을 만드는 이유 → 주 적용 대상이 자바 엔터프라이즈 기술을 사용하는 서버환경 → 높은 성능 요구됨. → 클라이언트에서 요청이 올 때마다 각 로직을 담당하는 오브젝트를 새로 만든다면? → 부하가 걸리면 서버가 감당하기 어려움.
  • 엔터프라이즈 분야에서는 서비스 오브젝트 개념을 일찍부터 사용함.
  • 서블릿
    • 자바 엔터프라이즈 기술의 기본이 되는 서비스 오브젝트임.
    • 대부분 멀티스레드 환경에서 싱글톤으로 동작함.
    • 서블릿 클래스 하나당 하나의 오브젝트 생성, 사용자의 요청을 담당하는 여러 스레드에서 하나의 오브젝트를 공유해 동시 사용.
  • 애플리케이션 안에 제한 된 수의 오브젝트만 만들어서 사용하는 것이 싱글톤 패턴의 원리임.

싱글톤 패턴의 한계

  • private 생성자를 갖고 있기 때문에 상속할 수 없음.
    • 객체지향의 장점인 상속과 이를 이용한 다형성을 적용할 수 없음.
  • 싱글톤은 테스트하기가 힘듦.
  • 서버환경에서는 싱글톤이 하나만 만들어지는 것을 보장 못함.
  • 싱글톤의 사용은 전역 상태를 만들 수 있기 때문에 바람직하지 못함.
    • 싱글톤의 스태틱 메소드를 이용해 언제든지 싱글톤에 쉽게 접근할 수 있기 때문에 전역 상태로 사용되기 쉬움. → 전역 상태를 갖는 것은 객체지향 프로그래밍에서는 권장되지 않는 프로그래밍 모델임.

싱글톤 레지스트리

  • 싱글톤 레지스트리(singleton registry) → 싱글톤 패턴에는 여러 가지 단점이 있기 때문에, 스프링은 직접 싱글톤 형태의 오브젝트를 만들고 관리하는 기능을 제공함.
  • 장점
    • 스태틱 메소드와 private 생성자를 사용해야 하는 비정상적인 클래스가 아니라 평범한 자바 클래스를 싱글톤으로 활용하게 해줌.
  • 스프링이 빈을 싱글톤으로 만드는 것은 오브젝트의 생성 방법을 제어하는 IoC 컨테이너로서의 역할임.

1.6.2 싱글톤과 오브젝트의 상태

  • 싱글톤은 멀티스레드 환경이라면 여러 스레드가 동시에 접근해서 사용할 수 있음. → 상태 관리에 주의를 기울여야함.
  • 기본적으로 싱글톤이 멀티스레드 환경에서 서비스 형태의 오브젝트로 사용되는 경우에는 무상태(stateless)방식으로 만들어져야 함. → 다중 사용자의 요청을 한꺼번에 처리하는 스레드들이 동시에 싱글톤 오브젝트의 인스턴스 변수를 수정하는 것은 위험함.

1.6.3 스프링 빈의 스코프

  • 스프링이 관리하는 오브젝트 → 빈의 스코프(scope)
  • 스프링 빈의 기본 스코프 → 싱글톤

1.7 의존관계 주입(DI)

1.7.1 제어의 역전(IoC)과 의존관계 주입

  • 객체지향적인 설계나, 디자인 패턴, 컨테이너에서 동작하는 서버 기술을 사용하면 자연스럽게 IoC를 적용하거나 그 원리로 동작하는 기술을 사용하게 됨.
  • 스프링 IoC 기능의 대표적인 동작원리는 주로 의존관계 주입(dependency injection)이라고 불림.
  • 스프링은 DI 컨테이너 라고 불림.

1.7.2 런타임 의존관계 설정

의존관계(Dependency Relationship)

  • 두 개의 클래스 또는 모듈이 의존관계에 있다고 말할 때는 항상 방향성을 부여해줘야 한다.
  • 의존관계란?
    <클래스의 의존관계 다이어그램>
    • A가 B에 의존하고 있음.
    • B가 변하면 A에 영향을 미침.
    • 한쪽의 변화가 다른 쪽에 영향을 주는 것임.

UserDao의 의존관계

  • 인터페이스에 대해서만 의존관계를 만들어두면 인터페이스 구현 클래스와의 관계는 느슨해지면서 변화에 영향을 덜 받는 상태가 됨. → 결합도가 낮아짐.
  • 클래스와 인터페이스를 통해 드러나는 의존관계 말고, 런타임 의존관계도 있음.
  • DI ?
    • 오브젝트 생성 후 런타임 시에 의존관계를 맺는 대상(실제 사용대상) 오브젝트를 의존 오브젝트(dependent object)라고 함.
    • 의존관계 주입은 다음의 세 조건 충족하는 작업임.
      • 클래스 모델이나 코드는 런타임 시점의 의존관계가 드러나지 않는다. 그러기 위해서는 인터페이스에만 의존하고 있어야 한다.
      • 런타임 시점의 의존관계는 컨테이너나 팩토리 같은 제 3의 존재가 결정한다.
      • 의존관계는 사용할 오브젝트에 대한 레퍼런스를 외부에서 제공해줌으로써 만들어진다.
    • 의존관계 주입의 핵심은 설계 시점에는 알지 못했던 두 오브젝트의 관계를 맺도록 도와주는 제3의 존재가 있다는 것임.
    • DI에서 말하는 제3의 존재는 바로 관계설정 책임을 가진 코드를 분리해서 만들어진 오브젝트임. → 애플리케이션 컨텍스트, 빈 팩토리, IoC 컨테이너 등이 모두 외부에서 오브젝트 사이의 런타임 관계를 맺어주는 책임을 지는 제3의 존재임.

1.7.3 의존관계 검색과 주입

  • 의존관계 검색(dependency lookup)
    • 외부 컨테이너에게 IoC로 맡기지만, 이를 가져올 때는 메소드나 생성자를 통한 주입 대신 스스로 컨테이너에게 요청하는 방법을 사용한다.
    • 의존관계 검색 방법은 코드 안에 오브젝트 팩토리 클래스나 스프링 API가 나타남. → 의존관계 주입 방식 코드가 더 깔끔함.
    • DI와 DL은 적용 방법에 차이가 있음.
    • 의존관계 검색 방식에서는 검색하는 오브젝트는 자신이 스프링의 빈일 필요가 없음.
      • 의존관계 주입을 원하는 오브젝트는 먼저 자기 자신이 컨테이너가 관리하는 빈이 돼야함.
  • 스프링의 IoC 컨테이너인 애플리케이션 컨텍스트는 getBean() 메소드를 제공함. → 의존 관계 검색에 사용됨.
  • DI 받는다?
    • 단순한 오브젝트 주입이 아니라 DI 개념을 따르는 주입임을 이해해야함.

1.7.4 의존관계 주입의 응용

  • DI의 장점은 관심사의 분리(SoC)를 통해 얻어지는 높은 응집도에서 나옴.
  • 스프링을 공부하는 건 DI를 어떻게 활용해야 할지 공부하는 것임.

1.7.5 메소드를 이용한 의존관계 주입

  • 의존관계 주입 시 반드시 생성자를 사용해야하는 것은 아님.
  • DI 방법
    • 수정자 메소드를 이용한 주입
      • 외부에서 오브젝트 내부의 애트리뷰트 값을 변경하려는 용도로 주로 사용됨.
      • 메소드 이름 정하는 것이 중요함. 가능한 의미있고 단순한 이름 사용하자. (e.g interface - ConnectionMaker → method - setConnectionMaker())
    • 일반 메소드를 이용한 주입

1.8 XML을 이용한 설정

  • 다양한 방법을 통해 DI 의존관계 설정정보를 만들 수 있음.
    • XML

1.9 정리

  • 스프링의 관심은 오브젝트와 그 관계임.
  • 오브젝트를 어떻게 설계, 분리, 개선하고 어떤 의존관계를 가질지 결정하는 일은 스프링이 아니라 개발자의 역할이며 책임임.

참고 자료