스터디/[토비의 스프링 3.1 Vol 1] (2025.03)

[토비의 스프링 3.1 Vol 2] 1장. 오브젝트와 의존관계 (~1.2.2)

ttoance 2025. 6. 14. 08:00
반응형

1장.IoC 컨테이너와 DI 

1.1 IoC 컨테이너 : 빈 팩토리와 애플리케이션 컨텍스트 

  • 스프링 애플리케이션에서는 오브젝트의 생성과 관계설정, 사용 제거 등의 작업을 애플리케이션 코드 대신 독립된 컨테이너가 담당한다. 
    • 이를 컨테이너가 코드 대신 오브젝트에 대한 제어권을 갖고 있다고 해서 IoC라고 부른다. 
    • 스프링에서는 IoC를 담당하는 빈 팩토리 또는 애플리케이션 컨텍스트라고 부른다. 
    • 빈 팩토리와 애플리케이션 컨텍스트는 각각 기능 대표하는 BeanFactory와 ApplicationContext라는 두 개의 인터페이스로 정의되어 있다. 
      • ApplicationContext는 BeanFactory 인터페이스를 상속받고 있다고 보면 된다. 
      • 실제 스프링 컨테이너 또는 IoC 컨테이너라고 말하는 것은 바로 이 ApplicationContext 인터페이스를 구현한 클래스의 오브젝트이다. 

 

 

1.1.1 IoC 컨테이너를 이용해 애플리케이션 만들기

  • 가장 간단하게 만드는 방법은 ApplicationContext의 구현 클래스의 인스턴스를 만들면 된다. 
StaticApplicationContext ac = new StaticApplicationContext();
  • 이렇게 만들어지는 컨테이너가 IoC컨테이너로 동작하려면 1) POJO 클래스와 2) 설정 메타정보가 필요하다. 

 

POJO 클래스 

  • 애플리케이션의 핵심 코드 담고 있는 POJO 클래스가 준비되어야 한다. 
  • 각가 기능에 충실하게 독립적으로 설계된 POJO 클래스 만들고, 결합도 낮은 유연한 관계 가질 수 있도록 인터페이스 이용해 연결해준다. 
    • Hello는 Printer인터페이스 사용하고, StringPrinter는 Printer 인터페이스 구현하도록 만든다. 
    • 런타임 시에 오브젝트 연결해주는 IoC 컨테이너의 도움을 받는다. 

 

설정 메타정보 

  • POJO 클래스들 중에서 애플리케이션에서 사용할 것 선정하고 이를 IoC컨테이너가 제어할 수 있도록 메타정보를 만들어야 한다. 
  • 스프링 컨테이너가 관리하는 오브젝트를 빈bean 이라고 한다. IoC컨테이너가 필요로 하는 설정 메타정보는 이 빈을 어떻게 만들고 어떻게 동작하게 할 것인가에 관한 정보다. 
  • 스프링의 설정 메타정보는 XML파일이 아니다. 스프링이 XML에 담긴 내용 읽어서 설정 메타정보로 활용하지만, 스프링이 XML로 된 설정 메타정보 가졌다는 말은 틀렸다. 
  • 스프링의 설정 메타정보는 BeanDefinition 인터페이스로 표현되는 추상 정보로, 애플리케이션 컨텍스트는 이 BeanDefinition으로 만들어진 메타정보 담은 오브젝트 사용해 IoC와 DI 작업 수행한다. 
  • BeanDefintion 인터페이스로 정의되는, 빈 메타정보는 다음과 같다. 
    • 빈 아이디, 이름, 별칭 : 빈 오브젝트를 구분할 수 있는 식별자 
    • 클래스 또는 클래스 이름 : 빈으로 만들 POJO 클래스 또는 서비스 클래스 정보 
    • 스코프 : 싱글톤, 프로토타입과 같은 빈의 생성 방식과 존재 범위 
    • 프로퍼티 값 또는 참조 : DI에 사용할 프로퍼티 이름과 값 또는 참조하는 빈의 이름
    • 생성자 파라미터 값 또는 참조 : DI에 사용할 생성자 파라미터 이름과 값 또는 참조할 빈의 이름
    • 지연된 로딩 여부, 우선 빈 여부, 자동와이어링 여부, 부모 빈 정보, 빈팩토리 이름 등 

 

 

  • 스프링 애플리케이션이란 POJO 클래스와 설정 메타정보 이용해 IoC 컨테이너가 만들어주는 오브젝트 조합이라고 할 수 있다. 
  • IoC컨테이너가 관리하는 빈은 오브젝트 단위지 클래스 단위가 아니다. 
    • 보통 클래스당 하나의 오브젝트 만들지만, 경우에 따라서 하나의 클래스를 여러 개의 빈으로 등록해두기도 한다. 
    • 예를 들어, 사용할DB가 여러개면 SimpleDriverDataSource 클래스로 된 빈 여러 개 등록하고 다른 DB설정 지정해 사용할 수 있다. 

 

 

1.1.2 IoC컨테이너의 종류와 사용 방법 

StaticApplicationContext

  • 코드를 통해 빈 메타정보 등록하기 위해 사용한다. 
  • 스프링의 기능에 다한 학습 테스트 만들 때 제외하면 실제로 사용되지 않는다. 
  • StaticApplicationContext는 실전에 사용해서는 안된다. 테스트 목적으로 코드 통해 빈 등록하고 컨테이너가 어떻게 동작하는지 확인하고 싶을 때 대비해 기억만 해두면 된다. 

 

GenericApplicationContext

  • 가장 일반적인 애플리케이션 컨텍스트의 구현 클래스며 실전에서 사용될 수 있는 모든 기능 갖추고 있는 애플리케이션 컨텍스트이다. 
  • StaticApplicationContext와 달리 XML파일과 같은 외부 리소스에 있는 빈 설정 메타정보를 리더 통해 읽어와서 메타정보로 전환해서 사용한다. 
  • 스프링 이용해서 GenericApplicationContext를 직접 이용할 일이 있을까 ?
    • 대부분 스프링 사용 개발자라면 없다. 
    • 스프링 자체를 확장해서 새로운 프레임워크를 만들거나, 스프링 사용하는 독립형 애플리케이션 만들지 않는 한 GenericApplicationContext를 직접 이용할 필요는 없다. 
    • ex, JUnit 테스트는 테스트 내에서 사용할 수 있도록 애플리케이션 컨텍스트를 자동으로 만들어준다. 이때 생성되는 애플리케이션 컨텍스트가 GenericApplicationContext 이다. 

 

GenericXmlApplicationContext 

  • 코드에서 GenericApplicationContxt를 사용하는 경우에는 번거롭게 XmlDefinitionReader를 직접 만들지 않고, 두 개 클래스가 결합된 GenericXmlApplicationContext를 사용하면 된다. 
  • GenericXmlApplicationContext는 XmlBeanDefinitionReader내장하고 있어서, XML 파일 읽어들이고 refresh() 통해 초기화 하는것까지 한 줄로 끝낼 수 있다. 

 

WebApplicationContext

  • ApplicationContext를 확장한 인터페이스로스프링 애플리케이션에서 가장 많이 사용되는 애플리케이션 컨텍스트이다. 
  • 가장 많이 사용되는 건, XML 설정 파일 사용하도록 만들어진 XmlWebApplicationContext이다. 애노테이션을 이용한 설정 리소스만 사용한다면 AnnotationConfigWebApplicationContext를 쓰면 된다. 
  • 스프링IoC 컨테이너는 빈 설정 메타정보 이용해 빈 오브젝트 만들고 DI작업 수행한다. 이후, 실행하기 위해서는 자바 애플리케이션의 main() 메소드처럼 특정 메소드 호출해야 한다.
  • 테스트나 독립형 애플리케이션이라면, 이런 기둥 역할을 맡은 빈을 사용하려면 IoC컨테이너에서 getBean() 통해 오브젝트를 가져와야 한다. 이후로는 의존관계를 타고 필요한 오브젝트가 호출하면서 애플리케이션이 동작할 것이다. 
  • 웹 어플리케이션은 main() 메소드를 호출할 방법이 없으며 사용자도 여럿이서 사용하게 된다. 그래서 서블릿 컨테이너가 브라우저로부터 오는 HTTP 요청을 받아서 해당 요청에 매핑되어 있는 서블릿을 실행해주는 방식으로 동작한다. 
  • 서블릿은 웹 애플리케이션이 시작될 때 미리 만들어둔 웹 어플리케이션 컨텍스트에서 빈 오브젝트로 구성된 애플리케이션의 기둑 역할을 해줄 빈을 요청해서 받아둔다. 그리고 미리 지정된 메소드를 호출함으로써 스프링 컨테이너가 DI 방식으로 구성해둔 애플리케이션의 기능이 시작한다.
    • 이를 실행해주는 기능을  DispatcherServlet이라고 한다. 
    • 스프링이 제공해준 서블릿을 web.xml에 등록하는 것만으로 웹 환경에서 스프링 컨테이너가 만들어지고 애플리케이션을 실행하는 데 필요한 준비가 끝난다. 

 

 

1.1.3 IoC 컨테이너 계층구조 

부모 컨텍스트 이용한 계층구조 효과 

  • 모든 애플리케이션 컨텍스트는 부모 애플리케이션 컨텍스트를 가질 수 있다. 
    • 계층구조 안의 모든 컨텍스트는 각자 독립적인 설정정보 이용해 빈 오브젝트를 만들고 관리한다. 
    • DI를 위해 빈을 찾을때는 부모 애플리케이션 컨텍스트의 빈까지 모두 검색한다. 
    • 중요한 건 자신의 부모 컨텍스트에게만 빈 검색을 요청하고 자식 컨텍스트에는 요청하지 않는다는 검이다. 

 

  • 1) 미리 만들어진 애플리케이션 컨텍스트의 설정을 그대로 가져다가 사용하면서 그 중 일부 빈만 설정 변경하고 싶다면, 애플리케이션 컨텍스트 두 개 만들어서 하위 컨텍스트에서 바꾸고 싶은 빈들을 다시 설정한다. 
    • 기존 설정 수정하지 않고 사용하지만 일부 빈 구성을 바꾸고 싶은 경우, 애플리케이션의 컨텍스트의 계층구조를 만드는 것이 편리하다. 
  • 2) 계층구조 이용하는 또 한 가지 이유는 여러 애플리케이션 컨텍스트가 공유하는 설정을 만들기 위해서이다. 

 

1.1.4 웹 애플리케이션의 IoC 컨테이너 구성 

서버에서 동작하는 애플리케이션에서 스프링 IoC컨테이너 사용하는 방법 
ㄴ 웹 모듈 안에 컨테이너 두는 방법 (일반적으로 두 가지방식 모두 사용해 만든다)
  ㄴ 스프링 애플리케이션 요청 처리하는 서블릿 안에서 만든다. 
  ㄴ 웹 애플리케이션 레벨에서 만든다. 
ㄴ 엔터프라이즈 애플리케이션 레벨에 두는 방법 
  ㄴ 독립적으로 배치 가능한 웹 모듈 형태 war 로 배포한다. ex, 프론트 컨트롤러 패턴
  
  
* 프론트 컨트롤러 패턴 : 몇 개의 서블릿이 중앙집중식으로 모든 요청 다 받아서 처리하는 방식 
ㄴ 자바 서버 기술이 등장했던 초기에는 war배포 시
   url당 하나의 서블릿을 만들어 등록하고 독립적인 기능을 담당하게 했다.
ㄴ 최근에는 많은 웹 요청 받을 수 있는  대표 서블릿을 두고, 공통적인 선행 작업 수행하게 한 후에, 
   각 요청 기능 담당하는 핸들러라고 블리는 클래스를 호출하는 방식으로 개발하는 경우가 일반적이다.

 

 

 

웹 애플리케이션의 컨텍스트 계층구조 

  • 웹 애플리케이션 레벨에 등록되는 컨테이너는 보통 로트 웹 애플리케이션 컨텍스트라고 불린다. 
  • 일반적으로는 스프링의 애플리케이션 컨텍스트를 가지면서 프론트 컨트롤러 역할을 하는 서블릿은 하나만 만들어 사용한다. 
    • 왜 계층구조로 만들까 ? 그 이유는 전체 애플리케이션에서 웹 기술에 의존적인 부분과 그렇지 않은 부분을 구분하기 위해서다. 스프링 이용하는 웹 애플리케이션이라고 해서 반드시 웹 기술 사용하지 않고 데이터 액세스 계층이나 서비스 계층은 스프링 사용하고, 웹 담당하는 프레젠테이션 계층은 스프링 외의 기술을 사용할 수 있다. 

 

웹 애플리케이션 컨텍스트 구성 방법 

1) 컨텍스트 계층구조 만드는 것 

- 서블릿 컨텍스트와 루트 애플리케이션 컨텍스트 계층구조 

  • 가장 많이 사용되는 기본적인 구성 방법 
  • 스프링 웹 기술 사용하는 경우 웹 관련 빈들은 서블릿 컨텍스트에, 나머지는 루트 애플리케이션 컨텍스트에 등록한다. 
  • 스프링 웹 에외도 웹 프레임워크나 HTTP 요청 통해 동작하는 각종 서비스를 함께 사용할 수 있다. 

2) 컨텍스트 하나만 사용하는 장법 

- 루트 애플리케이션 컨텍스트 단일구조 

  • 스프링 웹 기술 사용하지 않고 서드파티 웹 프레임워크나 서비스 엔진만을 사용해서 프레젠테이션 계층을 만든다. 

- 서블릿 컨텍스트 단일 구조 

  • 스프링 웹 기술 사용하면서 스프링 외의 프레임워크나 서비스 엔진에서 스프링의 빈 이용하지 않을 생각이라면 루트 애플리케이션 컨텍스트를 생략한다. 
  • 대신 서블릿에서 만들어지는 컨텍스트에 모든 빈을 다 등록하면 된다. 

 

루트 애플리케이션 컨텍스트 등록

  • 서블릿의 이벤트 리스너를 이용한다. 
    • SevletContextListener 를 이용해서 웹 애플리케이션 시작될 때 루트 애플리케이션 컨텍스트 만들어 초기화하고, 웹 애플리케이션 종료될 때 컨텍스트 함께 종료하는 기능을 가진 리스너를 만들 수 있다. 
    • 웹 애플리케이션 web.xml 안에 리스너 선언을 넣어준다. 

  • 디폴트값
    • 애플리케이션 컨텍스트 클래스 : XmlWebApplicationContext
    • XML 설정파일 위치 : /WEB-INF/applicationContext.XML 
    • contextConfigLocation으로 설정값 바꿀 수 있다. 

 

서블릿 애플리케이션 컨텍스트 등록 

  • 스프링 웹 기능 지원하는 프론트 컨트롤러 서블릿은 DispatcherServlet이다. 
  • web.xml에서 등록해서 사용할 수 있다.

 

1.2 IoC/DI를 위한 빈 설정 매타정보 작성 

 

1.2.1 빈 설정 메타정보 

  • 몇 가지 필수항목 제외하면 컨테이너에 미리 설정된 디폴트 값이 그대로 적용된다. 
  • 빈 설정 메타정보 항목 중에서 가장 중요한 것은 클래스 이름이다. 추상 빈으로 정의하지 않는 한 클래스 정보는 반드시 필요하다. 
  • 그다음 필요한 것은 빈의 아이디 또는 이름이다. 
  • 이 두가지만 있으면 가장 간단한 빈 하나를 정의할 수 있다. 

 

1.2.2 빈 등록 방법 

방법1) XML:  <bean>태그 

  • <bean>이용하면 스프링 빈 메타정보의 거의 모든 항목 지정할 수 있어 세밀한 제어가 가능하다. 

 

방법2) XML: 네임스페이스와 전용 태그 

  • 여러 애플리케이션에서 반복적으로 자주 사용되면서 기술적인 설정 담당하거나 공통적인 서비스 선언하는데 사용하는 10가지 네임스페이스가 있다. 
    • <aop:pointcut>
    • <jdbc:embedded-database>
    • ...
  • 스프링이 제공해주는 것 외에도 개발자가 스스로 커스텀 태그 만들어서 적용할 수 있다. 

 

방법3) 자동인식을 이용한 빈 등록 : 스테레오타입 애노테이션과 빈 스캐너 

  • 특정 애노케이션이 붙은 클래스 자동으로 찾아서 빈으로 등록하게 해줄 수 있다. 
  • 자동으로 찾아서 빈으로 등록해주는 방식을 빈 스캐닝을 통한 자동인식 빈 등록 기능이라고 하고, 이런 스캐닝 작업 당당하는 오브젝트를 빈 스캐너라고 한다. 
  • (장점) 복잡한 XML 문서 생성과 관리에 따른 수고 덜어주고 개발 속도 향상시킨다. 
  • (단점) 애플리케이션에 등록될 빈이 어떤 것들이 있고, 그 정의는 어떻게 되는지를 한눈에 파악할 수 없다. 
  • (단점) XML처럼 상세한 메타정보 항목 지정할 수 없고, 클래스당 한 개 이상의 빈을 등록할 수 없다. 

 

방법4) 자바 코드에 의한 빈 등록 : @Configuration클래스의 @Bean 메소드

  • 자바 코드를 통해 오브젝트 생성하고 DI해주는 경우가 있다. 
  • 애노테이션 설정 지원하는 컨테이너에 간단히 등록시킬 수 있다. 
  • 단순한 빈 스캐닝 통한 자동인식으로 등록하기 힘든 기술 서비스 빈의 등록이나 컨테이너 설정용 빈을 XML없이 등록하려고 할 때 유용하게 쓰인다. 

  • 유용한 점 
    • 컴파일러나 IDE 통한 타입 검증이 가능하다.
    • 자동완성과 같은 IDE 지원 기능을 최대한 이용할 수 있다. 
    • 이해하기 쉽다
    • 복잡한 빈 설정이나 초기화 작업을 손쉽게 적용할 수 있다

방법5) 자바 코드에 의한 빈 등록 : 일반 빈 클래스의 @Bean메소드 

  • 매번 다른 오브젝트를 받게 된다. 
  • Bean메소드가 정의된 클래스 밖에서 실수로라도 호출할 수 없도록 Private로 선언해두고, 클래스 내부에서도 DI통해 참조하도록 하여 주의글 기울어야 한다. 
  • 언제 사용해야 할까 ?
    • 매우 밀접한 관계가 있는 경우, 특별히 종속적인 빈의 경우에 사용할 수 있다. 
반응형