Skip to main content

컨테이너 훑어보기

SpringAbout 2 min

원문 : https://docs.spring.io/spring-framework/docs/current/reference/html/core.html#beans-basicsopen in new window

org.springframework.context.ApplicationConext 인터페이스는 스프링 IoC 컨테이너를 대표하고 빈을 객체화, 구성, 초기화를 담당한다.
컨테이너는 어떤 객체를 객체화, 구성, 초기화해야되는지 구성 메타데이터를 읽어서 지침을 가져옵니다.
구성 메타데이터는 XML, 자바 어노테이션, 자바 코드로 표현됩니다.
이를 통해 어플리케이션을 구성하는 객체와 이러한 객체간의 풍부한 상호종속성을 표현할 수 있습니다.

스프링에서 ApplicationContext 인터페이스의 다양한 구현체를 지원합니다.
독립형 어플리케이션에서 ClassPathXmlApplicationContextFileSystemXmlApplicationContext의 인스턴스를 생성하는 것이 일반적입니다.
XML이 구성 메타데이터를 정의하는데 전통적인 유형이지만 추가 메타형식에 대한 지원을 선언적 활성화를 위하여 작은 양의 XML 구성을 제공함으로써 컨테이너에게 자바 어노테이션이나 자바 코드로 메타데이터 형식을 사용할 수 있습니다.

대분 어플리케이션 시나리오의 스프링 IoC 컨테이너에서 한개 이상 인스턴스에 대한 인스턴스화를 위해 명시적 사용자 코드를 작성할 필요는 없습니다.
예로 들어, 웹 어플리케이션 시나리오에서 어플리케이션의 web.xml 파일에 있는 상용구 웹 설명자 XML의 간단한 8줄이면 충분합니다. (웹 어플리케이션을 위한 편리한 ApplicationContext 인스턴스화 참고)
Spring Tools for Eclipseopen in new window(이클립스-제공 개발 환경) 를 사용하면, 몇번의 마우스 클릭이나 키 입력으로 쉽게 이 상용구 구성을 만들 수 있습니다.

아래의 다이어그램은 스프링이 어떻게 동작하는지에 대한 고차원적 뷰입니다.
어플리케이션 클래스가 구성 메타데이터와 결합이 되고 ApplicationContext가 생성되어 초기화된 뒤 완전히 구성되면 실행가능한 시스템이나 어플리케이션을 가지게 됩니다.

그림 1. 스프링 IoC 컨테이너

1.2.1 구성 메타데이터

직전 다이어그램에 보여주듯, 스프링 IoC 컨테이너는 구성 메타데이터 양식을 소비합니다.
이 구성 메타데이터는 어플리케이션 개발자가 스프링 컨테이너에게 어플리케이션의 객체를 어떻게 인스턴스화 하고 구성하고 모으는지 말해주는 것을 표현합니다.

구성 메타데이터는 전통적으로 단순하고 직관적인 XML 형식을 지원합니다. 이번 장에서 스프링 IoC 컨테이너에 대한 주요 컨셉과 특징을 전달하는데 사용됩니다.

Tips

XML 기반 메타데이터는 구성 메타데이터에서 허용되는 유일한 형식은 아닙니다.
스프링 IoC 컨테이너 자체는 구성 메타데이터가 실제 작성된 형식에서 완전히 분리됩니다.
최근에는 많은 개발자들이 스프링 어플리케이션에서 자바기반 구성을 선택하고 있습니다.

스프링 컨테이너에서 사용되는 다른 형식의 메타데이터는 다음과 같습니다.

스프링 구성은 컨테이너가 관리해야하는 하나 이상의 빈 정의로 구성됩니다.
XML기반 구성 메타데이터는 상위 <beans/> 요소 내부에 <bean/> 으로 빈을 구성합니다.
자바 구성은 일반적으로 @Configuration 클래스에 @Bean 어노테이션기반 함수를 사용합니다.

이 빈 정의는 어플리케이션을 구성하는 실제 객체에 해당합니다.
일반적으로 서비스 레이어 객체, 데이터 접근 객체 (DAO), 스트럿츠의 Action 인스턴스와 같은 프리젠테이션 객체, 하이버네이트의 SessionFactories 와 같은 인프라구조 객체 등등을 정의합니다.
일반적으로 도메인 객체를 만들고 로드하는 것은 DAO나 비즈니스 로직의 책임이기 때문에 컨테이너에서 세분화된 도메인 개체를 구성하지는 않습니다.
그러나 IoC 컨테이너 제어 밖에서 생성된 객체를 구성할 경우 AspectJ와의 스프링 통합을 사용하면 됩니다.
자세한 내용은 5.10.1 스프링에서 도메인객체의 의존성 주입을 AspectJ로 사용하기open in new window를 참고하시면 됩니다.

아래의 예제는 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="..." class="...">  
        <!-- collaborators and configuration for this bean go here -->
    </bean>

    <bean id="..." class="...">
        <!-- collaborators and configuration for this bean go here -->
    </bean>

    <!-- more bean definitions go here -->

</beans>
  • id : 개별 빈 정의를 식별하는 문자열
  • class : 빈의 유형을 정의하며, 정규화된 클래스 명을 사용합니다.

id 속성의 값은 협업객체를 참고합니다.
협업객체를 참조하는 XML은 이번 예제에는 없습니다.
자세한 내용은 4. 의존성를 참고하세요.

1.2.2 컨테이너 인스턴스화

ApplicationContext 생성자에 적용되는 위치 경로(들)은 컨테이너가 다양한 외부 리소스(로컬 파일시스템, 자바 CLASSPATH 등)에서 불러올 구성 메타데이터의 리소스문자열 입니다.

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

Tips

스프링 IoC 컨테이너에 대해 배운뒤, URI 문법으로 정의된 위치로부터 InputStream을 읽는 편리한 메커니즘을 제공하는 스프링의 Resource 추상화(Resources에서 안내)에 대해 더 알고싶을 것 입니다.
특히, Resource 경로는 어플리케이션 컨텍스트와 리소스 경로에서 설명하듯 어플리케이션 컨텍스트를 생성하는 데 사용됩니다.

아래 예제는 서비스 레이어 객체 (services.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">

    <!-- services -->

    <bean id="petStore" class="org.springframework.samples.jpetstore.services.PetStoreServiceImpl">
        <property name="accountDao" ref="accountDao"/>
        <property name="itemDao" ref="itemDao"/>
        <!-- additional collaborators and configuration for this bean go here -->
    </bean>

    <!-- more bean definitions for services go here -->

</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">
        <!-- additional collaborators and configuration for this bean go here -->
    </bean>

    <bean id="itemDao" class="org.springframework.samples.jpetstore.dao.jpa.JpaItemDao">
        <!-- additional collaborators and configuration for this bean go here -->
    </bean>

    <!-- more bean definitions for data access objects go here -->

</beans>

위에 언급한 예제에서 서비스 레이어는 PetStoreServiceImpl 클래스와 JpaAccountDao, JpaItemDao 유형의 두개 데이터 접근 객체(JPA 객체-관계 매핑 표준 기반)로 구성되어있습니다.
propertyname 요소는 자바빈 속성의 이름을 참조하며, ref 요소는 다른 빈 정의의 이름을 참조합니다.
idref 요소간의 연결은 협력하는 객체간 의존성을 표현합니다.
객체들의 의존성 구성에 관련된 상세한 내용은 의존성에서 확인하실 수 있습니다.

XML 기반 구성 메타데이터 작성

빈에 대한 정의가 여러개 XML 파일에 걸쳐있는 것이 유용하기도 합니다.
자주, 각각의 개별 XML 구성 파일이 아키텍처상 논리적 레이어나 모듈을 표현하기도 합니다.

이 모든 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>

위 예제에서 외부 빈 정의는 3개의 파일 (services.xml, messageSource.xml, themeSource.xml)에서 불러오게 됩니다.
모든 위치경로는 가져오기를 수행하는 정의 파일과의 상대경로입니다.
따라서 service.xml 파일은 가져오기를 하는 파일과 동일한 디렉터리나 클래스패스 위치에 있어야 합니다.
messageSource.xmlthemeSource.xml 은 가져오기를 하는 파일 위치 하위에 resources 위치안에 있어야 합니다.
이때 선두 슬래쉬는 무시됩니다.
그러나, 주어진 경로가 상대경로이기 때문에 슬래쉬를 사용하지 않는 것잊 좋습니다.
최상위 <beans/> 요소를 포함하여 가져오는 파일의 내용은 스프링 스키마에 따라 유효한 XML 빈 정의여야 합니다.

Tips

../ 상대경로를 사용해서 부모 디렉터리의 파일을 참조하는 것이 가능하지만 추천하지는 않습니다.
이렇게 하면 현재 어플리케이션 외부에 있는 파일에 대한 종속성이 생성됩니다.
특히, 런타임 처리 프로세스가 가장 근접한 클래스패스 루트를 선택하고 그것의 상위 디렉터리를 찾게되기 때문에 이 참조방식은 classpath: URL (예로, classpath:../services.xml) 에서는 추천되지 않습니다.
클래스패스 구성 변경으로 다른, 잘못된 디렉터리를 선택할 수 있게 됩니다.

항상 상대경로 대신 리소스의 전체위치를 사용할 수 있습니다.
예로들어 file:C:/config/services.xml 이나 classpath:/config/services.xml 와 같습니다.
그러나, 어플리케이션 구성을 특정 절대위치에 연결하고 있다는 점을 유의하시기 바랍니다.
일반적으로 이러한 절대 위치에 대한 간접참조를 유지하는 것을 선호합니다.
예로들어, 실행중 JVM 시스템 속성으로 처리될 ${...} 치환자와 같습니다.

네임스페이스 자체는 import 지시자 기능을 제공합니다.
스프링에서 제공하는 XML 네임스페이스 선택 (예, context, util)에서 일반 빈 정의 이상의 추가 구성기능을 사용할 수 있습니다.

Groovy 빈 정의 DSL

외부화 구성 메타데이터의 추가 예제로, 빈 정의는 Grails 프레임워크로 알려진 스프링 그루비 빈 정의 DSL로 표현될 수 있습니다.
일반적으로 아래의 예제에서 보여주는 구조와 같은 .groovy 파일에 구성되어있습니다.

beans {
    dataSource(BasicDataSource) {
        driverClassName = "org.hsqldb.jdbcDriver"
        url = "jdbc:hsqldb:mem:grailsDB"
        username = "sa"
        password = ""
        settings = [mynew:"setting"]
    }
    sessionFactory(SessionFactory) {
        dataSource = dataSource
    }
    myService(MyService) {
        nestedBean = { AnotherBean bean ->
            dataSource = dataSource
        }
    }
}

이 구성 스타일은 XML 빈 정의와 거의 동일하며 스프링 XML 구성 네임스페이스를 지원합니다.
importBeans 지시자를 통해 XML 빈 정의 파일을 불러올 수 있습니다.

1.2.3 컨테이너 사용하기

ApplicationContext는 다른 빈과 의존성의 레지스트리를 관리하는 확장된 팩토리 능력을 위한 인터페이스 입니다.
T getBean(String name, Class<T> requiredType) 함수를 사용해서 빈의 인스턴스를 얻을 수 있습니다.

ApplicationContext를 통해 빈에 대한 정의를 읽고 접근하는지 아래예제를 통해 보여주겠습니다.

// 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();

Groovy 구성에서 부트스트래핑이 매우 유사합니다.
Groovy방식인지 알 수 있도록 한 다른 컨텍스트 구현체(XML 빈 정의 또한 이해가능)를 사용합니다.
아래는 Groovy 구성에 대한 예제입니다.

ApplicationContext context = new GenericGroovyApplicationContext("services.groovy", "daos.groovy");

좀더 확장가능한 방식으로는 GenericApplicationContext 와 리더대리자 간의 조합입니다.
예로들어 - 아래 예제와 같이 XML 파일을 위한 XmlBeanDefinitionReader를 함께 사용하는 것 입니다.

GenericApplicationContext context = new GenericApplicationContext();
new XmlBeanDefinitionReader(context).loadBeanDefinitions("services.xml", "daos.xml");
context.refresh();

또한 아래 예제와 같이 Groovy 파일을 위한 GroovyBeanDefinitionReader를 함께 사용할 수 있습니다.

GenericApplicationContext context = new GenericApplicationContext();
new GroovyBeanDefinitionReader(context).loadBeanDefinitions("services.groovy", "daos.groovy")
context.refresh();

동일한 ApplicationContext 에 이러한 리더 대리자들을 혼합사용하여 다양한 구성 소스에서 빈 정의를 읽을 수 있습니다.

getBean 을 사용하여 빈에 대한 인스턴스를 받아올 수 있습니다.
ApplicationContext 인터페이스는 빈을 가져오는 다른 함수도 있지만 이상적으로는 어플리케이션 코드가 이것을 사용하면 안됩니다.
대신, 어플리케이션 코드가 getBean() 함수를 더이상 호출하지 않고 스프링 API에 의존성을 가지지 않는 것 입니다.
예로들어, 웹 프레임워크의 스프링 통합은 특정 빈에 메타데이터를 통해 정의한 의존성(autowired 어노테이션 등)을 기반으로 컨트롤러나 JSF-관리되는 빈 등와 같이 다양한 웹 프레임워크 컴포넌트에 대한 의존성 주입을 제공합니다.