[Spring 레퍼런스] 4장 IoC 컨테이너 #2

이 문서는 개인적인 목적이나 배포하기 위해서 복사할 수 있다. 출력물이든 디지털 문서든 각 복사본에 어떤 비용도 청구할 수 없고 모든 복사본에는 이 카피라이트 문구가 있어야 한다.



4.3 빈(Bean) 개요

스프링 IoC 컨테이너는 하나 이상의 beans을 관리한다. 이러한 빈은 XML <bean/> 정의 같은 컨테이너에 제공한 설정 메타데이터로 생성된다.

컨테이너 내부에서 이러한 빈 정의는 BeanDefinition 객체로 나타나고 이 객체는 (다른 정보들과 함께) 다음의 메타데이터를 포함하고 있다.

  • 패키지에 최적화된(package-qualified) 클래스 명: 보통 정의된 빈의 실제 구현클래스이다.
  • 빈의 행동에 대한 설정 요소들. 컨테이너에서 빈이 어떻게 동작해야 하는가에 대한 상태.(범위, 라이프사이클 콜백 등등)
  • 빈이 동작하는 데 필요한 다른 빈들에 대한 참조. 이러한 참조들을 협력객체(collaborators)나 의존성(dependencies)이라고 부른다.
  • 새로 생성된 객체에 설정해야 하는 그 외 설정값. 예를 들면 커넥션 풀을 관리하는 빈에서 사용해야 하는 커넥션의 수나 풀의 용량제한 등이다.
이 메타데이터는 각 빈 정의를 구성하는 프로퍼티 세트로 변환된다.

Table 4.1. 빈 정의

프로프티설명한 곳
class

Section 4.3.2, “빈의 인스턴스화”

name

Section 4.3.1, “빈 이름짓기”

scope

Section 4.5, “Bean scopes”

constructor arguments

Section 4.4.1, “의존성 주입”

properties

Section 4.4.1, “의존성 주입”

autowiring mode

Section 4.4.5, “Autowiring collaborators”

lazy-initialization mode

Section 4.4.4, “Lazy-initialized beans”

initialization method

Section 4.6.1.1, “Initialization callbacks”

destruction method

Section 4.6.1.2, “Destruction callbacks”


어떻게 특정 빈을 생성하는가에 대한 정보를 담고 있는 빈 정의에 대해 추가로 ApplicationContext 구현체도 사용자가 컨테이너 밖에서 생성해서 이미 존재하는 객체들을 등록할 수 있다. getBeanFactory() 메서드로 어플리케이션 컨텍스트의 BeanFactory에 접근해서 이러한 객체들을 등록한다. getBeanFactory() 메서드는 BeanFactory를 구현한 DefaultListableBeanFactory를 리턴한다. DefaultListableBeanFactory는 registerSingleton(..)와 registerBeanDefinition(..) 메서드로 이러한 등록을 지원한다. 하지만 일반적인 어플리케이션은 메타데이터 빈 정의에서 정의된 빈으로만 동작한다.


4.3.1 빈 이름짓기

모든 빈에는 하나 이상의 식별자가 있다. 이러한 식별자는 빈을 제공하는 컨테이너 내에서 반드시 유일해야 한다. 보통 빈에는 단 하나의 식별자가 있지만 하나 이상이 필요하다면 추가적인 식별자로 별칭(alias)을 생각해 볼 수 있다.

XML기반의 설정 메타데이터에서 id나 name 속성으로 빈의 식별자를 명시한다. id 속성으로 정확하게 하나의 id를 지정할 수 있다. 관례적으로 이 이름은 문자와 숫자로 작성하지만 ('myBean', 'fooService' 등등) 특수문자도 사용할 수 있다. 빈에 별도의 별칭을 사용하고 싶다면 name 속성으로 지정하면 되고 여러 개를 입력할 때는 콤마(,)나 세미콜론 (;)이나 공백으로 구분한다. 변경사항 문서를 보면 스프링 3.1 이전의 버전에서는 id 속성을 사용할 수 있는 문자를 제한하기 위해 xsd:ID로 사용했다. 스프링 3.1에서는 xsd:string 을 사용한다. XML 파서를 사용하지 않더라도 여전히 컨테이너가 빈 아이디가 유일해야 한다는 조건을 강제한다.

빈에 id나 name을 반드시 제공해야 하는 것은 아니다. id나 name을 명시하지 않는다면 컨테이너는 빈에 유일한 이름을 부여한다. 하지만 ref 요소나 Service Locator 스타일의 검색을 사용해서 빈을 이름으로 참조하고 싶다면 이름을 반드시 지정해야 한다. name을 지정하지 않는 이유는 내부 빈 과 협력객체 오토와이어링를 사용하는 것과 연관이 있다.


4.3.1.1 외부에서 정의된 빈의 별칭짓기

빈 정의에서 id 속성에서 명시한 이름과 조합하거나 name 속성에 여러 이름을 작성해서 빈에 하나 이상의 이름을 작성할 수 있다. 이러한 이름들은 같은 빈에 대한 별칭이다. 별칭은 컴포넌트 자체에 명시한 빈 이름을 사용해서 공통 의존성을 참조하는 각각의 컴포넌트를 어플리케이션에서 사용하는 상황 등에서 유용하다.

빈이 실제로 정의된 곳에 모든 별칭을 명시하는 것이 항상 적절한 것은 아니다. 때로는 다른 곳에서 정의된 빈에 대해서 별칭을 지정하는 것이 적절한 때도 있다. 이는 설정이 자신만의 객체 정의의 세트가 있는 여러 서브시스템에 분리된 대형 시스템에서 일반적이다. XML 기반의 설정 메타데이터에서 외부에서 정의된 빈에 별칭을 부여하기 위해 <alias/>를 사용할 수 있다.

빈 작명 관례
빈에 이름을 지을 때는 인스턴스의 필드 이름에 대한 표준 자바 관례를 사용한다. 즉, 빈 이름은 소문자로 시작하고 카멜케이스를 사용한다. 예를 들어 'accountManager', 'accountService', 'userDao', 'loginController' 등이 된다.(홑따옴표는 생략한다)

빈의 이름을 일관성 있게 지으면 설정을 읽기 쉽고 이해하기 쉽다. 스프링 AOP를 사용한다면 이름과 관련된 빈의 세트에 어드바이스(advice)를 적용할 때 큰 도움이 된다.

<alias name="fromName" alias="toName"/>

이 예제의 설정을 사용하면 같은 컨테이너에서 fromName라는 이름의 빈을 toName로도 참조할 수 있다.

예를 들어 서브시스템 A의 설정 메타데이터는 'subsystemA-dataSource'라는 이름으로 DataSource를 참조한다. 서브시스템 B의 설정 메타데이터는 'subsystemB-dataSource' 라는 이름으로 DataSource를 참조한다. 이 두 서브시스템을 사용해서 메인 어플리케이션을 구성했을 때 메인 어플리케이션은 'myApp-dataSource'라는 이름으로 DataSource를 참조한다. 이 3가지 이름이 같은 객체를 참조하게 하려면 MyAPP 설정 메타데이터에 다음의 별칭 정의를 추가해야 한다.

<alias name="subsystemA-dataSource" alias="subsystemB-dataSource"/>
<alias name="subsystemA-dataSource" alias="myApp-dataSource" />


이제 각 컴포넌트와 메인 어플리케이션은 유일하면서 다른 어떤 정의와도 충돌하지 않는다는 보장을 받은 이름을 통해 데이터소스를 참조할 수 있다. 물론 같은 빈을 참조한다.


4.3.2 빈의 인스턴스화

본질적으로 빈 정의는 하나 이상의 객체를 생성하는 방법이다. 컨테이너는 요청이 발생했을 때 이름있는 빈에 대한 방법을 검색하고 실제 객체를 생성하는(또는 획득하는) 빈 정의로 은닉화된 설정 메타데이터를 사용한다.

XML기반의 설정 메타데이터를 사용하면 <bean/> 요소의 class 속성에서 인스턴스화 된 객체의 타입(또는 클래스)를 명시한다. 이 class 속성은 내부적으로는 BeanDefinition 인스턴스의 Class 프로퍼티다. class 속성은 강제적이다. (예외적인 상황은 Section 4.3.2.3, “인스턴스 팩토리 메서드를 이용한 인스턴스화”와 Section 4.7, “Bean definition inheritance”를 참고해라.) 두 가지 방법의 하나로 Class 프로퍼티를 사용한다.

  • 보통은 컨테이너 스스로 빈의 생성자를 리플렉트하게 호출함으로써 직접 빈을 생성하는 경우에 생성되는 빈의 클래스를 명시한다. 약간은 new 오퍼레이터를 사용하는 자바 코드와 비슷하다.
  • 객체를 생성하기 위해 호출될 static 팩토리 메서드가 있는 실제 클래스를 명시한다. 컨테이너가 빈을 생성하려고 클래스에서 static, factory 메서드를 호출하는 경우는 일반적이지는 않다. static 팩토리 메서드의 호출에서 리턴받은 객체의 타입은 같은 클래스나 다른 클래스와 완전히 같을 것이다.


4.3.2.1 생성자를 이용한 인스턴스화

생성자로 빈을 생성하면 일반적인 모든 클래스는 스프링과 함께 사용할 수 있다. 어떤 특정한 인터페이스를 구현하거나 특정한 스타일로 코딩할 필요가 없다. 그냥 빈 클래스를 명시하는 것만으로도 충분하다. 하지만 빈을 명시하려고 사용하는 IoC의 종류에 따라 기본 생성자(비어있는 생성자)가 필요할 수도 있다.

스프링 IoC 컨테이너는 관리하고자 하는 거의 모든 클래스를 관리할 수 있다. 진짜 JavaBean만 관리할 수 있다는 제약 같은 건 없다. 많은 스프링 사용자들은 기본 생성자(아규먼트가 없는)만 있는 실제 JavaBean에 프로퍼티에 대한 적절한 setter와 getter를 사용하는 방법을 선호한다. 물론 컨테이너에서 예외적으로 빈 스타일이 아닌 클래스도 사용할 수 있다. 예를 들어 JavaBean 스펙을 전혀 따르지 않는 레거시 커넥션풀을 사용하더라도 스프링이 잘 관리할 수 있다.

내부 클래스명
static 중첩클래스에 대한 빈 정의를 설정하고 싶다면 내부 클래스의 binary 이름을 사용해야 한다.

예를 들어 com.example 패키지에 Foo라는 클래스가 있고 이 com.example 클래스에는 Bar라는 static 내부 클래스가 있다면 빈 정의의 'class' 속성의 값은 다음과 같을 것이다.

com.example.Foo$Bar

이름에서 $ 문자는 바깥쪽 클래스 이름과 내부 클래스 이름을 구분하기 위해 사용한다.

XML기반의 설정 메타데이터를 사용하면 다음과 같이 빈 클래스를 명시할 수 있다.

<bean id="exampleBean" class="examples.ExampleBean"/>

<bean name="anotherExample" class="examples.ExampleBeanTwo"/>


생성자에 아규먼트를 전달하거나(필요하다면) 객체가 생성된 후에 인스턴스에 프로퍼티를 설정하는 방법에 대해 자세히 알고 싶다면 의존성 주입을 참고해라.


4.3.2.2 정적 팩토리 메서드를 이용한 인스턴스화

정적 팩토리 메서드로 생성하는 빈을 정의할 때 static 팩토리 메서드가 있는 클래스를 지정하는 class 속성과 팩토리 메서드의 이름을 지정하는 factory-method 속성을 사용한다. 이 팩토리 메서드를 호출하면(뒤에서 설명할 선택적인 아규먼트로) 생성자로 생성한 빈과 동일하게 취급하는 살아 있는 객체를 리턴받는다. 레거시 코드에서 static 팩토리를 호출하는 것이 이러한 빈 정의의 한가지 사용법이다.

다음 빈 정의는 팩토리 메서드를 호출해서 빈이 생성될 것이라는 지정한다. 이 빈 정의는 리턴되는 객체의 타입(클래스)은 지정하지 않고 클래스의 팩토리 메서드만 지정했다. 이 예제에서 createInstance() 메서드는 반드시 정적 메서드여야 한다.

<bean id="clientService"
      class="examples.ClientService"
      factory-method="createInstance"/>


public class ClientService {
  private static ClientService clientService = new ClientService();
  private ClientService() {}

  public static ClientService createInstance() {
    return clientService;
  }
}

팩토리 메서드에 (선택적인) 아규먼트를 전달하고 팩토리에서 리턴된 객체의 인스턴스에 프로퍼티를 설정하는 메커니즘에 대한 자세한 내용은 의존성과 세부 설정 을 참고해라.


4.3.2.3 인스턴스 팩토리 메서드를 이용한 인스턴스화

정적 팩토리 메서드를 통한 인스턴스화와 비슷한 인스턴스 팩토리 메서드를 이용한 인스턴스화는 새로운 빈을 생성하기 위해 컨테이너에 존재하는 빈의 정적이 아닌 메서드를 호출한다. 이 메커니즘을 사용하려면 class 속성을 비워두고 factory-bean 속성에 현재 (또는 부모나 조상) 컨테이너에서 객체를 생성하기 위해 호출하는 인스턴스 메서드를 가지고 있는 빈의 이름을 지정한다. factory-method 속성에 팩토리 메서드의 이름을 설정한다.

<!-- createInstance()
        를 호출하는 메서드를 담고 있는 팩토리 빈 -->
<bean id="serviceLocator" class="examples.DefaultServiceLocator">
  <!-- 이 로케이터 빈으로 필요한 의존성을 주입한다 -->
</bean>

<!-- 팩토리 빈을 통해 생성될 빈 -->
<bean id="clientService"
      factory-bean="serviceLocator"
      factory-method="createClientServiceInstance"/>


public class DefaultServiceLocator {
  private static ClientService clientService = new ClientServiceImpl();
  private DefaultServiceLocator() {}

  public ClientService createClientServiceInstance() {
    return clientService;
  }
}

하나의 팩토리 클래스는 다음과 같이 하나 이상의 팩토리 메서드를 가질 수도 있다.

<bean id="serviceLocator" class="examples.DefaultServiceLocator">
  <!-- 이 로케이터 빈으로 필요한 의존성을 주입한다 -->
</bean>
<bean id="clientService"
      factory-bean="serviceLocator"
      factory-method="createClientServiceInstance"/>

<bean id="accountService"
      factory-bean="serviceLocator"
      factory-method="createAccountServiceInstance"/>


public class DefaultServiceLocator {
  private static ClientService clientService = new ClientServiceImpl();
  private static AccountService accountService = new AccountServiceImpl();

  private DefaultServiceLocator() {}

  public ClientService createClientServiceInstance() {
    return clientService;
  }

  public AccountService createAccountServiceInstance() {
    return accountService;
  }
}


이 접근은 팩토리 빈 스스로 의존성 주입 (DI)를 통해 관리되고 설정될 수 있다는 것을 보여준다. 의존성과 세부 설정 을 참고해라.

Note
스프링 문서에서 팩토리 빈은 스프링 컨테이너에 설정된 빈을 참조한다. 이 빈은 인스턴스나 정적 팩토리 메서드를 통해 객체를 생성하는 빈이다. 반면에 FactoryBean (대문자에 주의해라)은 스프링 고유의 FactoryBean 을 참조한다.

2012/01/26 01:13 2012/01/26 01:13
크리에이티브 커먼즈 라이센스
Creative Commons License

Leave a Reply

[로그인][오픈아이디란?]

Facebook Comments

[Spring 레퍼런스] 4장 IoC 컨테이너 #1

이 문서는 개인적인 목적이나 배포하기 위해서 복사할 수 있다. 출력물이든 디지털 문서든 각 복사본에 어떤 비용도 청구할 수 없고 모든 복사본에는 이 카피라이트 문구가 있어야 한다.



Part III. 코어 테크놀로지

레퍼런스 문서에서 이번 Part는 스프링에서 절대적으로 중요한 기술들을 모두 다룬다.

코어 테크놀로지 중에서 가장 중요한 것은 스프링 프레임워크의 제어의 역전(IoC) 컨테이너다. 스프링 프레임워크의 IoC 컨테이너의 철저한 처리는 스프링의 관점 지향 프로그래밍(AOP) 기술이 가진 광범위한 커버리지로 밀접하게 이어진다. 스프링 프레임워크의 자체 AOP 프레임워크는 개념적으로 이해하기 쉽고 자바 엔터프라이즈 프로그래밍에서 필요한 AOP 요구사항의 80% 정도를 성공적으로 다룬다.

스프링은 AspectJ (현재 기능 면에서 가장 강력하고 자바 엔터프라이즈 영역에서 확실히 가장 발전한 AOP 구현체이다.) 와 통합도 제공한다.

마지막으로 스프링 팀은 소프트웨어 개발에 테스트 주도 개발 (TDD) 도입을 확고하게 지지한다. 그래서 스프링은 통합테스트도 지원한다. (유닛테스트에 대한 베스트 프렉티스도 제공한다.) 스프링 팀은 IoC를 제대로 사용하면 유닛 테스트와 통합 테스트를 더 쉽게 할 수 있다는 점을 깨달았다. (setter 메서드와 클래스의 적절한 생성자가 있으면 service locator registry 등을 설정하지 않아도 테스트와 쉽게 연결할 수있다.) 테스팅을 다룬 챕터에서 이 부분을 알 수 있을 것이다.

  • Chapter 4, IoC 컨테이너
  • Chapter 5, Resources
  • Chapter 6, Validation, Data Binding, and Type Conversion
  • Chapter 7, Spring Expression Language (SpEL)
  • Chapter 8, Aspect Oriented Programming with Spring
  • Chapter 9, Spring AOP APIs
  • Chapter 10, Testing



4. IoC 컨테이너


4.1 Spring IoC 컨테이너와 빈즈(beans)의 도입

이번 챕터는 제어의 역전 (IoC) 원리에 대한 스프링 프레임워크의 구현체에 대해 설명한다. IoC는 의존성 주입 (DI) 으로도 알려다. 이는 객체가 함께 동작해야 하는 의존성을 정의하는 처리 과정이다. IoC는 생성자 아규먼트나 팩토리 메서드의 아규먼트 또는 객체 인스턴스 후에 설정된 프로퍼티나 팩토리 메서드에서 리턴받은 값으로 정의한다. 그다음 컨테이너는 빈이 생성될 때 의존성을 주입한다. 이 처리 과정은 빈 스스로 인스턴스화 하는 과정을 제어하거나 직접 클래스의 생성자를 사용해서 의존성을 정의하거나 또는 서비스 로케이터 패턴 같은 메니즘과 근본적으로 정반대이므로 제어의 역전 (IoC)이라고 이름 붙였다.

org.springframework.beans와 org.springframework.context 패키지는 스프링 프레임워크 IoC 컨테이너의 기반이다. BeanFactory 인터페이스는 어떤 타입의 객체도 다룰 수 있는 향상된 설정 메카니즘을 제공한다. ApplicationContext 는 BeanFactory의 서브 인터페이스다. ApplicationContext는 스프링의 AOP기능, 메시지 리소스 핸들링 (국제화(i18n)를 사용하려고), 이벤트 발생, 웹 어플리케이션의 WebApplicationContext같은 어플리케이션 계층에서 지정한 컨텍스트와 더 쉽게 통합할 수 있게 한다.

간단히 말하면 BeanFactory는 설정 프레임워크와 기본적인 기능을 제공하고 ApplicationContext는 에 엔터프라이즈급에 가까운 기능을 추가한다. ApplicationContext 는 BeanFactory의 슈퍼셋이고 이 챕터에서는 전적으로 스프링 IoC 컨테이너를 설명하는 데만 사용한다. ApplicationContext 대신 BeanFactory를 사용하는 방법에 대해 더 자세한 내용을 알고 싶다면 Section 4.15, “The BeanFactory”를 참고해라.

스프링에서 어플리케이션의 중추가 되고 스프링 IoC 컨테이너가 관리하는 객체를 빈(bean)이라고 부른다. 빈은 인스턴스화 되고 결집한 객체로 스프링 IoC 컨테이너가 관리한다. 빈은 어플리케이션에서 수많은 객체 중 하나일 뿐이다. 컨테이너가 사용한 설정 메타데이터는 빈과 빈 사이의 의존성에 반영된다.



4.2 컨테이너 개요

org.springframework.context.ApplicationContext 인터페이스는 스프링 IoC 컨테이너를 나타내며 앞에서 언급한 빈을 인스턴스화하고 설정하고 조합하는 데 책임이 있다. 컨테이너는 어떤 객체를 인스턴스로 만들고 설정하고 조합해야 하는지를 설정 메타데이터에서 알아낸다. 설정 메타데이터는 XML이나 자바 어노테이션, 자바 코드로 나타낸다. 설정 메타데이터는 어플리케이션을 구성하는 객체들을 나타내고 그러한 객체들 사이의 풍부한 상호 의존성을 나타낸다.

ApplicationContext 인터페이스의 다양한 구현체는 스프링 밖에서 제공된다. 단독 어플리케이션에서는 일반적으로 ClassPathXmlApplicationContext나 FileSystemXmlApplicationContext의 인스턴스를 생성한다. XML이 설정 메타데이터를 정의하는 보편적인 포맷이 되었지만, 자바 어노테이션이나 메타데이터 형식의 코드로 컨테이너에 설정을 알려줄 수 있다. 이러한 추가적인 메타데이터 포맷을 선언적으로 지원하도록 하는 소량의 XML 설정만 제공하면 된다.

대부분의 어플리케이션 시나리오에서 스프링 IoC 컨테이너의 인스턴스를 만드는 명시적인 사용자 코드는 필요하지 않다. 예를 들어 웹 어플리케이션 시나리오에서 어플리케이션의 web.xml에서 8줄 정도의 J2EE 웹 디스크립터 XML만으로도 보통 충분할 것이다.(Section 4.14.4, “Convenient ApplicationContext instantiation for web applications” 참고) 이클립스 기반의 개발환경인 SpringSource Tool Suite나 Spring Roo를 사용한다면 이러한 설정은 몇 번의 마우스 클릭이나 키보드 입력만으로도 생성할 수 있다.

다음 다이어그은 스프링이 어떻게 어떻게 동작하는지 보여준다. 어플리케이션의 클래스들은 설정 메타 데이터와 결합한다. 그래서 ApplicationContext 이 생성되고 인스턴스화 되면 완전히 설정이 완료되고 실행가능한 시스템이나 어플리케이션이 준비된다.

Spring IoC 컨테이너

Spring IoC 컨테이너



4.2.1 설정 메타데이터(Configuration metadata)

앞의 다이어그램에서 봤듯이 스프링 IoC 컨테이너는 설정 메타데이터 형식을 받아들인다. 이 설정 메타데이터를 통해 어플리케이션 개발자는 스프링 컨테이너가 어플리케이션의 객체를 어떻게 인스턴스화하고 설정하고 조합해야 하는지 지시할 수 있다.

설정 메타데이터는 전통적으로 간단하고 직관적인 XML 포맷을 사용한다. 이 챕터에서도 스프링 IoC 컨테이너의 핵심 개념과 기능을 설명하기 위해서 XML을 사용한다.

Note
XML기반의 메타데이터는 설정 메타데이터를 위한 유일한 형식이 아니다. 스프링 IoC 컨테이너 자체도 실제 작성된 설정 메타데이터의 형식과 완전히 분리되어 있다.

스프링 컨테이너에 다른 형식의 메타데이터를 사용하는 방법에 대해서는 다음을 참고해라.

  • Annotation-based configuration: 스프링 2.5에서 도입된 어노테이션 기반의 설정 메타데이터 지원.
  • Java-based configuration: 스프링 3.0을 시작하면서 Spring JavaConfig 프로젝트의 많은 기능이 스프링 프레임워크의 핵심부분이 되었다. 그러므로 XML파일 대신에 자바로 어플리케이션 클래스에 대한 빈을 외부에서 정의할 수 있다. 이 기능을 사용하려면 @Configuration, @Bean, @Import, @DependsOn 봐라.
스프링의 설정은 컨테이너가 반드시 관리해야 하는 최소한 하나 이상의 빈 정의로 이루어진다. XML기반의 설정 메타데이터는 최상위 <beans/> 엘리먼트 안에 <bean/> 엘리먼트로 이러한 빈을 설정한다.

이러한 빈 정의들은 어플리케이션을 구성하는 실제 객체들과 대응된다. 일반적으로 서비스계층 객체, 데이터 접근 객체(DAO), Struts Action 인스턴스같은 프리젠테이션 객체, Hibernate SessionFactories같은 인프라스트럭처 객체, JMS Queues등을 정의한다. 보통 이는 보통 도메인 객체를 생성하고 로드하는 DAO와 비즈니스 로직에 대한 책임이 있기 때문에 컨테이너에서 세분화된 도메인 객체를 설정하지 않는다. 하지만 IoC 컨테이너의 제어범위 밖에서 생성된 객체를 설정하기 위해 AspectJ를 스프링과 통합할 수 있다. Using AspectJ to dependency-inject domain objects with Spring를 참고해라.

다음 예제는 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
           http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">

  <bean id="..." class="...">
    <!-- 이 빈에 대한 추가적인 협력 객체나 설정은 여기에 작성한다 -->
  </bean>

  <bean id="..." class="...">
    <!-- 이 빈에 대한 추가적인 협력 객체나 설정은 여기에 작성한다 -->
  </bean>

  <!-- 추가적인 빈 정의는 여기에 작성한다 -->

</beans>

id 속성은 개별 빈 정의를 구분하기 위해 사용하는 문자열이다. class 속성은 빈의 타입을 정의하고 정규화된(fully qualified) 클래스 명을 사용한다. id 속성의 값은 협력 객체를 참조한다. 협력 객체를 참조하는 XML은 이 예제에 없다. 더 자세한 정보는 Dependencies를 참고해라.


4.2.2 컨테이너의 인스턴스화

스프링 IoC 컨테이너의 인스턴스화는 이해하기 쉽다. ApplicationContext 생성자에 제공한 위치 경로는 사실 리소스에 대한 문자열이다. 컨테이너는 이 경로로 로컬파일 시스템 같은 다양한 외부리소스나 자바 CLASSPATH 등에서 설정 메타데이터를 로드한다.

ApplicationContext context = new ClassPathXmlApplicationContext(new String[] {"services.xml", "daos.xml"});

Note
스프링의 IoC 컨테이너를 공부하고 나면 Chapter 5, Resources에서 설명하는 스프링의 Resource에 대해서 궁금해질 것이다. Resource는 URI 문법으로 정의된 위치에서 입스트림을 읽는 편리한 메니즘을 제공한다. 특히, Resource 경로는 Section 5.7, “Application contexts and Resource paths”에서 설명하는 어플리케이션 컨텐스트를 구성하는 데 사용한다.


다음 예제는 서비스 계층 객체 (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
           http://www.springframework.org/schema/beans/spring-beans-3.0.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
           http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">

  <bean id="accountDao"
      class="org.springframework.samples.jpetstore.dao.ibatis.SqlMapAccountDao">
    <!-- 이 빈에 대한 추가적인 협력 객체나 설정은 여기에 작성한다 -->
  </bean>

  <bean id="itemDao" class="org.springframework.samples.jpetstore.dao.ibatis.SqlMapItemDao">
    <!-- 이 빈에 대한 추가적인 협력 객체나 설정은 여기에 작성한다 -->
  </bean>

  <!-- 데이터 접근 객체에 대한 추가적인 빈 정의는 여기에 작성한다 -->

</beans>


앞의 예제에서 서비스계층은 PetStoreServiceImpl 클래스로 이루어져 있고 SqlMapAccountDao와 SqlMapItemDao 타입의 두 데이터 접근 객체들은 iBatis 객체/관계 매핑(Object/Relational mapping) 프레임워크에 기반을 둔다. property name 요소는 JavaBean 프로퍼티의 이름을 참조한다. ref 요소는 또 다른 빈 정의의 이름을 참조한다. id와 ref 요소의 결합은 협력 객체들 사이의 의존성을 나타낸다. 객체의 의존성을 설정하는 방법에 대한 자세한 내용은 Dependencies를 참고해라.


4.2.2.1 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>


앞의 예제에서는 services.xml, messageSource.xml, themeSource.xml 의 3개 파일에서 외부 빈 정의를 로드했다. 모든 위치 경로는 임포트하는 파일의 상대경로이므로 services.xml는 반드시 같은 디렉터리에 있거나 같은 클래스패스 경로에 있어야 한다. 그리고 messageSource.xml 와 themeSource.xml는 임포트하는 파일 하위에 resources 위치에 있어야 한다. 이 예제에서 보듯이 맨 앞의 슬래시(/)는 무시되고 경로는 상대경로가 되므로 맨 앞에 슬래시를 사용하지 않는 것이 더 좋은 형식이다. 임포트된 파일의 내용은 최상위에 <beans/>가 있는 스프링 스키마나 DTD를 따르는 유효한 XML 빈 정의여야 한다.

Note
"../"를 사용해서 부모 디렉터리의 파일을 참조하는 것도 가능하지만 별로 권하지 않는다. 부모 디렉터리를 참조하면 현재 어플리케이션 밖에 있는 파일에 대한 의존성을 만든다. 특히 이러한 참조는 "가장 가까운" 클래스패스 루트를 선택하고 루트의 부모 디렉터리를 검색하는 런타임 처리인 "classpath:" URL(예를 들면 "classpath:../services.xml")에서는 사용하지 말아야 한다. 클래스패스 설정을 변경하면 다른 디렉리나 잘못된 디렉터리를 선택할 수 있다.

항상 상대경로 대신 정규화된(fully qualified) 리소스 경로를 사용할 수 있다. 예를 들면 "file:C:/config/services.xml"나 "classpath:/config/services.xml"와 같은 형식이다. 하지만 절대경로를 사용하면 어플리케이션 설정이 특정 절대경로에 대한 깊은 결합도가 생긴다는 것을 알아야 한다. 보통 이러한 절대 경로를 우회하는 방법을 더 선호한다. 예를 들면 "${...}" 플레이스홀더를 사용해서 런타임시에 JVM 시스템 프로퍼티로 교체한다.


4.2.3 컨테이너의 사용

ApplicationContext는 여러 빈의 등록과 빈의 의존성을 유지하는 향상된 팩토리 기능을 제공하는 인터페이스다. T getBean(Stringname, Class<T> requiredType) 메서드를 사용하면 빈의 인스턴스를 얻을 수 있다.

ApplicationContext는 다음과 같이 빈 정의를 읽고 빈에 접근할 수 있게 한다.

// 생성과 설정 빈
ApplicationContext context = new ClassPathXmlApplicationContext(new String[] {"services.xml", "daos.xml"});

// 설정된 인스턴스 획득
PetStoreServiceImpl service = context.getBean("petStore", PetStoreServiceImpl.class);

// 설정된 인스턴스 사용
List userList service.getUsernameList();


getBean()를 사용해서 빈의 인스턴스를 얻는다. ApplicationContext 인터페이스에는 빈을 얻어오는 몇 가지 메서드가 더 있지만, 이상적으로는 어플리케이션 코드는 이러한 메서드를 사용하지 말아야 한다. 사실 어플리케이션 코드는 getBean() 메서드를 전혀 호출하지 말아야 한다. 그래서 스프링 API에 대한 의존성을 전혀 갖지 말아야 한다. 예를 들어 웹 프레임워크에 대한 스프링의 통합은 컨트롤러와 JSF로 관리되는 빈처럼 여러 가지 웹 프레임워크 클래스에 대한 의존성 주입을 제공한다.
2012/01/26 01:11 2012/01/26 01:11
크리에이티브 커먼즈 라이센스
Creative Commons License

Leave a Reply

[로그인][오픈아이디란?]

Facebook Comments

  • Categories

    List (719)
    BlaBlaBla~ (110)
    JAVA (116)
    Scala (48)
    .NET (21)
    PHP (1)
    Database (27)
    Development (100)
    Publishing (34)
    Javascript (117)
    node.js (39)
    CoffeeScript (10)
    Ruby on Rails (11)
    RIA (10)
    Web 2.0 & Semantic (46)
    Ubuntu (6)
    Mobile (23)
  • Tag Cloud

  • Calendar

    «   2012/01   »
    1 2 3 4 5 6 7
    8 9 10 11 12 13 14
    15 16 17 18 19 20 21
    22 23 24 25 26 27 28
    29 30 31        
  • Archives

  • JavaScript JS Documentation: JS RegExp lastIndex, JavaScript RegExp lastIndex, JS RegExp .lastIndex, JavaScript RegExp .lastIndex
    SAVE THE
    DEVELOPERS <!>
    Upgrade IE 6 Now!
  • Recent Posts

  • Recent Comments

  • Recent Trackbacks

  • Recent My Delicious

  • Site Stats

    • Total hits: 1394836
    • Today: 646
    • Yesterday: 1883
  • 2198

    1456

    0

    -30 days

    today : 646

    Google PageRank Checker Powered by  MyPagerank.Net