박서희연구소

[Spring] 스프링 IoC 컨테이너 본문

○ Programming [Web]/Spring

[Spring] 스프링 IoC 컨테이너

SEOHUI PARK 2022. 5. 19. 16:20
반응형

이 글은 스프링의 공식 문서를 읽고 정리 및 나의 생각대로 가공한 글이다.

스프링 IoC 컨테이너와 빈 소개

IoC는 의존성 주입(Dependency Injection, DI)이라고도 한다.

과정은 이렇다.

  1. 객체가 생성자 Arguments 또는 팩토리 메서드에 대한 Arguments에서 반환
  2. 객체 인스턴스에 설정된 속성을 통해서만 의존성을 정의
  3. 컨테이너는 빈을 생성할 때 의존성 주입

이 과정은 근본적으로 클래스의 직접 구성과 같은 매커니즘을 사용하여 의존성이 인스턴스화 또는 위치를 제어하게 되는 빈 자체의 역전(Inversion of Control)이다.

 

IoC 컨테이너의 기본 패키지 구성으로는 org.springframework.beansorg.springframework.context 가 있다.

BeanFactory 인터페이스는 모든 객체의 유형을 관리할 수 있는 고급 설정에 유용한 메커니즘을 제공하며, 서브 인터페이스로는 ApplicationContext가 있다.

ApplicationContext가 지원하는 기능

  • Spring의 AOP 기능과 더 쉽게 통합
  • 메시지 자원 처리(국제화)
  • 이벤트 퍼블리싱
  • 웹 애플리케이션 사용을 위한 WebApplicationContext와 같은 애플리케이션 계층 특정 컨텍스트

요약하면 BeanFactory는 Configuration Framework와 기본 기능을 제공하며, ApplicationContext는 더 많은 엔터프라이즈 기능을 지원한다.

(ApplicationContext와 BeanFactory의 스펙은 더 방대하니 자세한 설명은 지금 다루지 않음)

 

빈이란 용어가 나오니 빈에 대해서 간략하게 설명하면, 스프링에서 애플리케이션의 백본을 형성하고, IoC 컨테이너에 의해 관리되는 객체로 설명은 이렇다.

  • 빈은 IoC 컨테이너에 의해 인스턴스화되며, 조합 및 관리되는 객체
  • 빈은 간단하게, 애플리케이션의 많은 객체들 중 하나일 뿐임
  • 빈과 빈 간의 의존성은 컨테이너에 사용하는 Configuration Metadata에 반영

컨테이너 개요

org.springframework.context.ApplicationContext 인터페이스는 스프링 IoC 컨테이너를 나타내며, 빈의 인스턴스화, 구성 및 조합을 담당한다.

  • 컨테이너는 Configuration Metadata를 읽어 객체의 인스턴스화, 구성, 조합에 대한 지침을 얻음
  • Configuration Metadata는 XML, Java Annotation 또는 Java 코드로 표시되며, 이는 애플리케이션을 구성하는 객체와 객체 사이의 풍부한 상호 의존성을 표현함

XML은 Configuration Metadata의 전통적인 포맷으로 사용되었고, 이러한 추가 Metadata 형식에 대한 지원을 선언적으로 활성화하기 위해 소량의 XML 설정을 제공함으로써, 컨테이너가 Metadata 형태로 Java Annotation 또는 코드를 사용할 수 있도록 지시할 수 있다.

 

아래 그림은 High-Level에서 스프링이 어떻게 작동되는지 볼 수 있다.

스프링 IoC 컨테이너

Configuration Metadata

스프링 IoC 컨테이너는 Configuration Metadata 형식을 사용하며, 이를 사용함으로써 애플리케이션 개발자로서 컨테이너에 애플리케이션의 객체를 인스턴스화, 구성 및 조합하도록 지시하는 방법을 나타낸다.

(Configuration Metadata는 전통적으로 간단하고 직관적인 XML 형식으로 제공)

 

Spring Configuration은 컨테이너가 관리해야 하는 적어도 하나, 그리고 하나 이상의 빈을 정의하는 것으로 구성된다.

  • XML 기반은 최상위 <beans/> 요소 내부에 <bean/> 요소로 구성
  • Java Configuration은 @Configuration 클래스 내에서 @Bean Annotation이 달린 메서드를 사용

이렇게 빈을 정의하면 애플리케이션을 구성하는 실제 객체가 되며, 일반적으로 서비스 계층 객체, 데이터 액세스 객체와 같은 프레젠테이션 객체, Hibernate SessionFactories와 같은 객체를 정의한다.

 

XML기반 Configuration Metadata는 아래와 같은 구조이다.

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
        https://www.springframework.org/schema/beans/spring-beans.xsd">

    <bean id="..." class="...">  
    </bean>

</beans>
  • id 속성은 빈 정의를 식별하는 문자열
  • class 속성은 빈의 유형을 정의

컨테이너 인스턴스화

ApplicationContext 생성자의 위치 경로는 컨테이너가 로컬의 파일 시스템, Java CLASSPATH 등과 같은 다양한 외부의 리소스에서 Configuration Metadata를 로드할 수 있도록 하는 문자열이다.

ApplicationContext context = new ClassPathXmlApplicationContext("services.xml", "daos.xml");

다음은 서비스 계층 객체(services.xml) Configuration 파일이다.

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
        https://www.springframework.org/schema/beans/spring-beans.xsd">

    <bean id="petStore" class="org.springframework.samples.jpetstore.services.PetStoreServiceImpl">
        <property name="accountDao" ref="accountDao"/>
        <property name="itemDao" ref="itemDao"/>
    </bean>

</beans>

다음은 데이터 액세스 객체 daos.xml 파일이다.

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
        https://www.springframework.org/schema/beans/spring-beans.xsd">

    <bean id="accountDao"
        class="org.springframework.samples.jpetstore.dao.jpa.JpaAccountDao">
    </bean>

    <bean id="itemDao" class="org.springframework.samples.jpetstore.dao.jpa.JpaItemDao">
    </bean>

</beans>

서비스 계층은 PetStoreServiceImpl 클래스와 JpaAccountDaoJpaItemDao 유형의 두 데이터 액세스 객체로 구성된다.

  • property name 요소는 JavaBean 속성의 이름을 참조하며, ref 요소는 다른 빈 정의의 이름을 참조
  • idref 요소 간의 이러한 연결은 협업 객체 간의 의존성을 나타냄

XML기반의 Configuration Metadata 작성

빈 정의를 여러개의 XML 파일에서 하는 것이 유용할 때도 있으며, 애플리케이션 컨텍스트 생성자를 사용하여 빈 정의를 로드할 수 있고, 이 생성자는 여러개의 Resource 위치 사용이 가능하다.

<import/> 요소를 하나 이상 사용하여 다른 파일에서 빈 정의를 로드한다.

<beans>
    <import resource="services.xml"/>
    <import resource="resources/messageSource.xml"/>
    <import resource="/resources/themeSource.xml"/>

    <bean id="bean1" class="..."/>
    <bean id="bean2" class="..."/>
</beans>

해당 파일에서 외부 빈 정의는 services.xml, messageSource.xmlthemeSource.xml 세 파일에서 로드된다.

모든 위치 경로를 가져오는 파일에 상대적이므로 services.xml은 가져오는 파일과 동일한 디렉터리 또는 클래스 경로에 있어야 하며, messageSource.xmlthemeSource.xml은 가져오는 파일 위치 아래 resources의 위치에 있어야 한다.

(위 코드와 같이 선행되는 슬래시는 무시되지만, 이런 경로는 상대적이므로 슬래시를 전혀 사용하지 않는 것이 좋음)

최상위 <beans/> 요소를 포함해 가져오는 파일의 내용은 스프링 스키마에 따라 유효한 XML 빈 정의여야 한다.

컨테이너 사용

ApplicationContext는 다른 빈과 그 의존성의 레지스트리를 유지할 수 있는 고급의 팩토리를 위한 인터페이스이다.

T getBean(String name, Class<T> requiredType) 메서드를 사용해 빈 인스턴스를 검색할 수 있다.

// create and configure beans
ApplicationContext context = new ClassPathXmlApplicationContext("services.xml", "daos.xml");

// retrieve configured instance
PetStoreService service = context.getBean("petStore", PetStoreService.class);

// use configured instance
List<String> userList = service.getUsernameList();

이렇듯 getBean을 사용해 빈의 인스턴스를 검색할 수 있다.

ApplicationContext 인터페이스에는 빈을 검색하기 위한 몇 가지 다른 메서드가 있지만 이상적으로는 애플리케이션 코드에서 이런 메서드를 사용하면 안 된다.

(실제 애플리케이션 코드에서는 getBean() 메서드에 대한 호출이 전혀 없어야 하므로 스프링 API에 대한 의존성이 전혀 없어야 함)

 

- 끝 -

반응형
Comments