[Info]Tags categorized posts and contents patterns..

[AJAX] Ajax Code E xamples.. [Book] About the book.. [CSS] CSS Code E xamples.. [DB] Sql Code E xamples.. [DEV] All development stor...

2016년 4월 12일 화요일

[Book] Nginx HTTP Server 한국어판..

출처 : Outsider's Dev Story https://blog.outsider.ne.kr/

Nginx HTTP Server 한국어판 - 6점
클레먼트 네델쿠 지음
김득권 옮김
에이콘출판

이벤트 기반의 웹서버인 nginx에 대한 책입니다. nginx(엔진엑스라고 읽습니다.)는 세계에서 가장 많이 사용되는 웹서버인 Apache 웹서버를 대체할 차세대 웹서버로 주목받고 있습니다. 해외에서는 이미 많이 사용되고 있는 걸로 알고 있고 국내에서도 최근에 많은 주목을 받고 있습니다. 책에 대한 좋고 나쁨을 말하기 전에 일단 현재 국내에서 nginx에 대한 책은 이 책 뿐이기 때문에 nginx의 문서Wiki만 보고 사용하기가 어려워서 참고할 내용이 필요하다면 이 책 외에는 선택권이 없습니다.

PACKT책의 컨셉은 약간 트랜드로 올라온 신기술을 빠르게 보급하고자 하는 의도로 생각하고 있는데(모든 책을 읽어본 것은 아닙니다.) 이 책도 비슷한 컨셉을 가지고 있습니다.
Nginx에 입문하고자 하는 사람들을 타게팅으로 하고 있는 것으로 보이며 전체적으로 봤을때는 번역도 괜찮은 편이고 기초적인 내용을 잘 다루고 있습니다.

1장은 작업환경준비인데 PuTTY를 이용한 쉘 접속부터 쉘명령어, 리눅스 파일시스템, 시스템 관리도구등을 설명하고 있습니다. 사실 이부분은 nginx에 대한 내용이라기 보다는 리눅스 서버에 접속해서 작업을 하고자 할 때 알아야 하는 배경지식에 가깝습니다. 리눅스를 어느 정도 쓰는 사람들에게는 너무 기초적인 내용일 수도 있지만 리눅스를 잘 모르는 개발자들에게는 nginx를 만지기 전에 이런 사용법에 대해서도 힘들어 할 것이므로 간단히 리눅스의 사용체계를 이용하는데 괜찮아 보입니다. 다른 이유로 리눅스의 기본적인 쉘을 이해할 필요가 있을 때 1장을 읽어보면 약간 도움이 될 듯 합니다.

2장 부터는 nginx의 설치가 나오는데 꽤 자세하게 설명해 주기 때문에 설치하는데 어려움이 없을 듯 합니다. 이 책은 nginx의 활용에 대한 부분은 기본적이 사용방법에 더 주력하고 있습니다. 그래서 3,4,5장에 걸쳐서 설정에 대한 내용이 나옵니다. 당연히 웹서버인 만큼 대부분의 사용법은 설정이나 마찬가지므로 설정파일의 문법과 여러가지 모듈에 대해서 어떻 옵션이 있고 어떤 용도에 사용하는지 설명하고 있습니다. 좀 사용하다보면 이러한 옵션들은 책보다는 레퍼런스 문서를 찾아보는게 빠르겠지만 처음 nginx를 배우면서 어떤 기능들이 있는지 파악하는데 괜찮다고 생각합니다.

6,7장은 본격적으로 웹서버에서 가장 많이 사용할 리버스 프록시로서의 역할에 대해서 설명하고 있습니다. 여기서 설명하는 것은 FastCGI를 통해서 PHP와 파이썬의 장고와 연결하는 방법과 뒷단에 기존 아파치를 두고 nginx를 리버스 프록시로 사용하는 방법을 설명합니다. 제가 PHP나 파이썬쪽을 쓰지 않아서 그런지 CGI자체를 만져본지가 너무 오래되서 사실 FastCGI는 많이 쓰는 것인지 잘 모르겠습니다. 보통은 뒤에 WAS를 두고(언어가 무엇이든지) nginx를 리버스 프록시로 쓰는 것이 가장 일반적인 형태(꼭 리버스 프로식의 형태는 아닐수도 있지만요)가 아닌가 생각했는데 생각보다 리버스 프록시에 대한 설명은 약하지 않았나 생각합니다. 실제로 리버스 프록실 제대로 사용하려면 책으로 기본 개념 정도만 잡고 세부적인 부분은 문서나 인터넷을 검색해야 할 것으로 보입니다. 그리고 어차피 리버스 프록시라서 내용을 응용해서 사용하면 똑같기는 하지만 뒷단을 WAS가 아닌 아파치를 두어서(아파치의 기능때문에 완전히 없애지 못할때의 과도기 적인 방법으로 이 책에서 제시한 방법입니다.) 아파치를 같이 설명하면서 하기 때문에 초보자들에게는 WAS와 연결하는 리버스 프록시로 사용하려면 약간 헷갈릴 수 있겠다는 생각이 듭니다. 8장은 apache를 nginx로 교체할 때를 위한 설정의 비교입니다. 8장은 읽을때는 재미없는 장이기는 하지만 apache를 교체해야 한다면 꽤 참고가 될만한 내용이라 생각됩니다.

아파치를 너무 오래 써왔기 때문에 nginx로의 교체에 대해서 의구심을 가지는 개발자가 많이 있다고 생각합니다. 사실 기술에서 이제 대세니까 무조건 바꾸어야 한다고 말하고 싶진 않습니다. 하지만 nginx가 더 위력을 발휘할 서비스들이 있기 때문에 기본적인 내용을 파악해 두는 것은 좋다고 생각하고 그런 면에서 기본적인 내용을 다뤄주는 이 책은 괜찮은 가이드를 줍니다.  다만 아쉬운 점은 이 책의 원서는 2010년 7월에 나왔는데 역서는 2011년 10월에나 나왔습니다. nginx는 그동안 많은 발전을 이루어서 이 책은 0.7.66 버전을 기반으로 하고 있고 nginx의 최신 버전은 1.1.15입니다. 계속 nginx를 쓰던 것이 아니라 얼마나 달라졌는지 알 수 없기는 하지만 버전의 차이를 봤을 때는 달라진 부분은 좀 있을 것으로 보입니다. 이 두 버전간의 차이를 이해하는 것도 독자에겐 약간 부담이라 그런 부분에 대해서 설명이 있었으면 하는 아쉬움이 남더군요.

이 책에서 nginx를 묘사한 다음 내용이 참 인상적이더군요.

아파치는 마치 마이크로소프트 워드 같다. 수백만 개의 옵션이 있지만 사람들은 단지 여섯개만 사용한다. 그 여섯 개의 옵션은 엔진엑스에도 있고 그 중 다섯 개는 아파치보다 50배나 빠르다.


[JAVA]4장 IoC 컨테이너 #2..

출처 : Outsider's Dev Story https://blog.outsider.ne.kr/

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

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

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


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


Table 4.1. 빈 정의
프로프티설명한 곳
classSection 4.3.2, “빈의 인스턴스화”
nameSection 4.3.1, “빈 이름짓기”
scopeSection 4.5, “Bean scopes”
constructor argumentsSection 4.4.1, “의존성 주입”
propertiesSection 4.4.1, “의존성 주입”
autowiring modeSection 4.4.5, “Autowiring collaborators”
lazy-initialization modeSection 4.4.4, “Lazy-initialized beans”
initialization methodSection 4.6.1.1, “Initialization callbacks”
destruction methodSection 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)를 적용할 때 큰 도움이 된다.


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

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

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


Xml
1
2
<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기반의 설정 메타데이터를 사용하면 다음과 같이 빈 클래스를 명시할 수 있다.


Xml
1
2
<bean id="exampleBean" class="examples.ExampleBean"/>
<bean name="anotherExample" class="examples.ExampleBeanTwo"/>

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

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

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


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

Java
1
2
3
4
5
6
7
8
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 속성에 팩토리 메서드의 이름을 설정한다.


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

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

Java
1
2
3
4
5
6
7
8
public class DefaultServiceLocator {
  private static ClientService clientService = new ClientServiceImpl();
  private DefaultServiceLocator() {}

  public ClientService createClientServiceInstance() {
    return clientService;
  }
}

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


Xml
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
<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"/>

Java
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
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 을 참조한다.

[JAVA]4장 IoC 컨테이너 #1..

출처 : Outsider's Dev Story https://blog.outsider.ne.kr/

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

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
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
<?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 등에서 설정 메타데이터를 로드한다.



Xml
1
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
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
<?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
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
<?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/> 요소를 사용해서 다른 파일의 빈 정의를 로드할 수 있다. 예를 들면 다음과 같다.



Xml
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
<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는 다음과 같이 빈 정의를 읽고 빈에 접근할 수 있게 한다.



Xml
1
2
3
4
5
6
7
8
// 생성과 설정 빈
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로 관리되는 빈처럼 여러 가지 웹 프레임워크 클래스에 대한 의존성 주입을 제공한다.

[JAVA]3장 Spring 3.1의 새로운 기능과 개선된 점..

출처 : Outsider's Dev Story https://blog.outsider.ne.kr/

레퍼런스의 3장은 3.1을 소개하는 장인데 문서에도 나와있듯이 3.1 RC1이 나올 시기정도에 문서가 업데이트된 것 같습니다. 현재는 3.1 GA가 릴리즈 되어 있지만 일단 문서상태 그대로 옮깁니다. 3.1에 대한 자세한 내용을 살펴보시려면 다른 글을 더 찾아봐야 할 겁니다. 이 포스팅은 다음의 스프링소스 라이센스를 따릅니다.

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

3. Spring 3.1의 새로운 기능과 개선된 점
스프링 3.0에서 도입된 기능 위에서 스프링 3.1은 현재 개발중에 있다. 이 글을 쓰는 시점에 스프링 3.1 RC1를 릴리즈할 준비를 하고 있다.

3.1 새로운 기능
다음은 스프링 3.1의 새로운 기능들이다. 대부분의 기능은 아직 레퍼런스 문서에 적용되지 않았지만 Javadoc에는 적용되었다. Javadoc에는 완전히 검증된 클래스명이 나와있다.

3.1.1 캐시(Cache) 추상화

  • Chapter 28, Cache Abstraction
  • 캐시 추상화 (스프링소스 팀 블로그)

3.1.2 빈(Bean) 선언 프로파일
  • XML 프로파일 (스프링소스 팀 블로그)
    @Profile 소개 (스프링소스 팀 블로그)
    org.springframework.context.annotation.Configuration의 JavaDoc 참고
    org.springframework.context.annotation.Profile의 JavaDoc 참고

3.1.3 환경(Environment) 추상화
  • 환경 추상화 (스프링소스 팀 블로그)
  • org.springframework.core.env.Environment Javadoc의 JavaDoc 참고

3.1.4 PropertySource 추상화
  • 통인된 Property 관리 (스프링소스 팀 블로그)
  • org.springframework.core.env.Environment Javadoc의 JavaDoc 참고
  • org.springframework.core.env.PropertySource Javadoc의 JavaDoc 참고
  • org.springframework.context.annotation.PropertySource의 JavaDoc 참고

3.1.5 스프링의 XML 네임스페이스와 동일한 코드
자주 사용하는 <context:component-scan/>, <tx:annotation-driven/>, <mvc:annotation-driven>의 스프링 XML 네임스페이스 엘리먼트와 동일한 기능을 대부분 @Enable 어노테이션의 형식으로 사용할 수 있다. 이 기능은 스프링 3.0에서 도입된 @Configuration 클래스와 결합해서 사용하도록 설계했다.

  • org.springframework.context.annotation.Configuration 의 JavaDoc 참고
  • org.springframework.context.annotation.ComponentScan 의 JavaDoc 참고
  • org.springframework.transaction.annotation.EnableTransactionManagement 의 JavaDoc 참고
  • org.springframework.cache.annotation.EnableCaching의 JavaDoc 참고
  • org.springframework.web.servlet.config.annotation.EnableWebMvc 의 JavaDoc 참고
  • org.springframework.scheduling.annotation.EnableScheduling 의 JavaDoc 참고
  • org.springframework.scheduling.annotation.EnableAsync 의 JavaDoc 참고
  • org.springframework.context.annotation.EnableAspectJAutoProxy 의 JavaDoc 참고
  • org.springframework.context.annotation.EnableLoadTimeWeaving 의 JavaDoc 참고
  • org.springframework.beans.factory.aspectj.EnableSpringConfigured 의 JavaDoc 참고

3.1.6 Hibernate 4.x 지원
  • 새로 추가된 org.springframework.orm.hibernate4 패키지의 클래스에 대한 Javadoc을 참고해라

3.1.7 @Configuration 클래스와 빈 선언 프로파일을 지원하는 TestContext 프레임워크
@ContextConfiguration 어노테이션은 이제 스프링 TestContext를 설정하는 @Configuration 클래스를 제공한다. 새로 추가된 @ActiveProfiles 어노테이션은 ApplicationContext 통합테스트에서 엑티브 빈 선언 프로파일을 선언적으로 설정을 지원한다.

  • Spring 3.1 M2: Testing with @Configuration Classes and Profiles (SpringSource Team Blog)
  • Spring 3.1 M2: @Configuration 클래스와 Profile을 이용한 테스트 (스프링 소스 팀 블로그)
  • Section 10.3.5, “Spring TestContext Framework” 참고
  • the section called “Context configuration with @Configuration classes”와 org.springframework.test.context.ContextConfiguration 의 Javadoc 참고
  • org.springframework.test.context.ActiveProfiles 의 Javadoc 참고
  • org.springframework.test.context.SmartContextLoader 의 Javadoc 참고
  • org.springframework.test.context.support.DelegatingSmartContextLoader 의 Javadoc 참고
  • org.springframework.test.context.support.AnnotationConfigContextLoader 의 Javadoc 참고

3.1.8 c: 더 간단한 생성자 주입을 위한 네임스페이스
  • Section 4.4.2.7, “XML shortcut with the c-namespace”

3.1.9 비표준 JavaBean의 setter에 대한 주입 지원
Spring 3.1이전에는 프로퍼티 메서드에 주입을 하기 위해 JavaBean 프로퍼티 시그니쳐 규칙을 엄격하게 따라야 했다. 즉, 모든 'setter'는 반드시 리턴값이 없어야 한다.(void) 이제 스프링 XML에서 setter가 어떤 객체타입을 리턴하도록 명시하는 것이 가능하다. 이는 메서드 체이닝(method-chaining)으로 API를 디자인할 때 setter 메서드가 'this'에 대한 참조를 리턴하도록 하는데 유용하다.

3.1.10 서블릿 컨테이너의 서블릿 3 코드기반 설정 지원
전통적인 web.xml을 프로그래밍적으로 대체하는 서블릿 3.0의 ServletContainerInitializer에 기반을 둔 WebApplicationInitializer를 새로 추가했다.


3.1.11 Servlet 3 MultipartResolver에 대한 지원
  • org.springframework.web.multipart.support.StandardServletMultipartResolver 의 Javadoc 참고

3.1.12 persistence.xml 없이 JPA EntityManagerFactory 부트스트랩하기
표준 JPA에서 퍼시스턴트 유닛은 지정된 jar파일의 META-INF/persistence.xml파일에 정의되고 @Entity 클래스를 찾는다. 많은 경우에 persistence.xml은 유닛의 이름과 의존하는 기본설정이나 필요한 외부설정(사용하려는 DataSource같은) 이외의 정보는 담고 있지 않다.


그래서 스프링 3.1은 대안을 제공한다. LocalContainerEntityManagerFactoryBean는 @Entity클래스를 찾을 패키지를 지정하는 'packagesToScan' 속성을 지원한다. 이는 네이티브 Hibernate 설정에서 AnnotationSessionFactoryBean의 같은 이름의 속성이나 스프링의 정규 스프링 빈을 찾는 컴포넌트 스캔 기능과 유사하다. 사실 엔티티 스캔을 하는 패키지명시하는 JPA설정은 XML없이도 가능하다. 특히 스프링 빈의 컴포넌트 스캔에 기반한 어플리케이션과 잘 매치되고 코드기반의 서블릿 3.0 초기화를 사용해서 부트스트랩하는 것도 가능하다.

3.1.13 어노테이션이 붙은 컨트롤러의 처리를 위해 새롭게 추가된 HandlerMethod 기반의 지원 클래스
Spring 3.1은 어노테이션이 붙은 컨트트롤러가 요청을 처리하도록 지원하는 클래스의 새로운 셋을 추가했다.

  • RequestMappingHandlerMapping
  • RequestMappingHandlerAdapter
  • ExceptionHandlerExceptionResolver
이러한 클래스들은 이미 존재하는 클래스들은 대체한다.

  • DefaultAnnotationHandlerMapping
  • AnnotationMethodHandlerAdapter
  • AnnotationMethodHandlerExceptionResolver
어노테이션이 붙은 컨트롤러의 지원 클래스들이 더 커스터마이징할 수 있고 쉽게 확장할 수 있도록 해야 한다는 많은 요청을 수용해서 새로운 클래스들을 개발했다. 전에는 커스텀 어노테이션이 붙은 컨트롤러 메서드의 아규먼트 리졸버를 설정할 수 있었지만 새로운 지원 클래스를 사용하면 모든 지원메서드의 아규먼트와 리턴값의 타입에 대한 처리를 커스터마이징할 수 있다.

  • org.springframework.web.method.support.HandlerMethodArgumentResolver 의 Javadoc 참고
  • org.springframework.web.method.support.HandlerMethodReturnValueHandler 의 Javadoc 참고
다음으로 주목할 만한 차이점은 @RequestMapping 메서드를 나타내는 HandlerMethod 추상화의 도입이다. HandlerMethod 추상화는 handler 인스턴스로 새로 추가된 클래스에 의해 언제든지 사용된다. 예를 들어 HandlerInterceptor는 handler를 Object에서 HandlerMethod로 캐스팅 할 수 있고 타겟 컨트롤러 메서드나 타겟 컨트롤러 메서드의 어노테이션 등에 접근할 수 있다.

MVC 네임스페이스의 기본설정이나 @EnableWebMvc를 사용한 자바기반의 설정으로 새로운 클래스를 사용하도록 할 수 있다. 기존의 클래스들은 계속해서 사용할 수 있지만 새로운 클래스를 사용하기를 더욱 권장한다.

3.1.14 @RequestMapping의 "consume"과 "produce" 상태
'Accept'헤더로 지정된 타입을 만드는 것(produce)과 마찬가지로 'Content-Type'헤더로 지정된 미디어타입을 메서드로 소비(consume)하는 것에 대한 지원이 개선되었다. Section 16.3.2.4, “Consumable Media Types”와 Section 16.3.2.5, “Producible Media Types”를 참고해라.

3.1.15 Flash 속성과 RedirectAttributes
flash 속성은 이제 FlashMap에 저장할 수 있고 리다이렉트했을 때도 유지되도록 HTTP 세션에 저장할 수 있다. 스프링 MVC에서 flash 속성에 대한 일반적인 지원을 살펴보려면 Section 16.6, “Using flash attributes”를 참고해라.

어노테이션이 붙은 컨트롤러에서 @RequestMapping 메서드는 RedirectAttributes타입의 메서드 아규먼트를 선언함으로써 flash 속성을 추가할 수 있다. RedirectAttributes타입의 메서드 아규먼트는 리다이렉트 시나리오에서 사용된 속성을 정확하게 가져오기 위해 사용할 수도 있다. 더 자세한 내용은 Section 16.3.3.10, “Specifying redirect and flash attributes”를 봐라.

3.1.16 향상된 URI 템플릿 변수
현재 요청의 URI 템플릿 변수를 더 다양한 곳에서 사용한다.

  • 요청을 @ModelAttribute 메서드 아규먼트에 바인딩할 때 요청 파리미터에 추가로 URI 템플릿 변수를 사용한다.
  • @PathVariable 메서드 아규먼트의 값은 렌더링하기 전에 모델에 합쳐진다. 단 JSON 직렬화나 XML 마샬랑처럼 자동화된 방법으로 생성하는 컨텐츠의 뷰는 제외다.
  • 리다이렉트 문자열은 URI 변수를 위한 플레이스홀더를 포함할 수 있다. (예를 들어 "redirect:/blog/{year}/{month}") 플레이스홀더를 확장했을 때 현재 요청의 URI 템플릿 변수를 자동으로 고려한다.
  • @ModelAttribute 메서드 아규먼트는 문자열에서 타겟 객체타임으로 변환하기 위해서 등록한 Converter나 PropertyEditor에서 제공받은 URI 템플릿 변수로 초기화 될 수 있다.

3.1.17 @RequestBody 컨트롤러 메서드 아규먼트상의 @Valid
@RequestBody 메서드 아규먼트는 @ModelAttribute 메서드 아규먼트와 유사하게 자동화된 유효성 확인은 호출하는 @Valid 어노테이션을 붙일 수 있다. MethodArgumentNotValidException가 발생하면 DefaultHandlerExceptionResolver가 처리하고 400 응답코드를 돌려준다.

3.1.18 컨트롤러 메서드 아규먼트 상의 @RequestPart 어노테이션
이 새로운 어노테이션은 "multipart/form-data" 요청의 컨텐츠에 대한 접근을 제공한다. Section 16.10.5, “Handling a file upload request from programmatic clients” 와 Section 16.10, “Spring's multipart (file upload) support”를 참고해라.

3.1.19 UriComponentsBuilder와 UriComponents
UriComponents 클래스를 새로 추가했다. UriComponents 클래스는 모든 URI 컴포넌트에 대한 접근을 제공하는 URI 컴포넌트의 불변(immutable) 컨테이너다. UriComponentsBuilder 클래스는 UriComponents 인스턴스의 생성을 돕는다. 이 두 클래스를 함께 사용하면 URI 템플릿 변수의 생성과 확장을 포함해서 URI를 준비하는 관점과 인코딩에 걸친 전 과정을 제대로 제어할 수 있다.

대부분의 경우에 새롭게 추가된 클래스들은 기존의 UriTemplate를 훨씬 유연하게 대체할 수 있다. 내부적으로 UriTemplate는 같은 클래스에 기반을 두고 있다.

ServletUriComponentsBuilder의 서브클래스는 서블릿 요청에서 정보를 복사하는 정적 팩토리 메서드를 제공한다. Section 16.7, “Building URIs”를 참고해라.


[JAVA]2장 Spring 3.0의 새로운 기능과 개선된 점..

출처 : Outsider's Dev Story https://blog.outsider.ne.kr/

이 포스팅은 다음의 스프링소스 라이센스를 따릅니다.

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

2. Spring 3.0의 새로운 기능과 개선된 점
스프링 프레임워크를 사용해 본 적이 있다면 스프링이 2개의 메이저 리비전을 지나왔다는 것을 알고 있을 것이다. 스프링 2.0은 2006년 10월에 릴리즈했고 스프링 2.5는 2007년 11월에 릴리즈했다. 이제 스프링 3.0으로 세 번째 개선을 하였다.

Java SE와 Java EE 지원
스프링 프레임워크는 이제 Java 5 기반이고 Java 6도 완전히 지원한다.

게다가 스프링은 J2EE 1.4와 Java EE 5와 호환성이 있으며 동시에 Java EE 6을 일찍부터 지원했다.

2.1 Java 5
제너릭(generic)이나 가변인자(varargs), 그 외 언어적 개선사항 같은 Java 5 기능의 이점을 취하도록 전체 프레임워크 코드를 수정했다. 코드의 하위호환성을 계속 유지하도록 최선을 다했다. 제너릭 컬렉션과 맵의 일관된 사용, 제너릭 팩토리빈(FactoryBean)의 일관된 사용, 스프링 AOP API에서 브릿지 메서드의 일관된 해결책을 제공한다. 제너릭 어플리케이션리스너(ApplicationListener)는 자동으로 특정이벤트의 타입만 받는다. TransactionCallback과 HibernateCallback같은 모든 콜백 인터페이스는 이제 제너릭 결과값을 선언한다. 전반적으로 스프링 핵심코드를 Java 5를 기반으로 새로 작성되고 최적화했다.

Java 5의 java.util.concurrent와의 닫힌 통합(close integration)을 위해 스프링의 TaskExecutor 추상화를 수정했다. ExecutorService 어댑터, ThreadFactory 통합 뿐 아니라 이제 Callable과 Future를 지원하는 퍼스트 클래스를 제공한다. 이는 가능한 한 JSR-236(Java EE 6을 위한 동시성 유틸리티)과 맞추었다. 게다가 새로운 @Async 어노테이션(또는 EJB 3.1의 @Asynchronous 어노테이션)으로 비동기 메서드 호출을 지원한다.

2.2 개선된 문서
스프링 레퍼런스 문서도 스프링 3.0의 수정사항과 새로운 기능을 반영해서 상당히 수정되었다. 이 문서에 오류가 없도록 노력하였음에도 약간의 에러가 있을 수 있다. 오타나 심각한 오류를 발견한다면 약간의 시간을 할애해서 이슈를 올려 스프링 팀에게 알려주기를 부탁한다.

2.3 새로운 글과 튜토리얼
스프링 3의 기능에 대한 좋은 글과 튜토리얼을 스프링 문서에서 볼 수 있다.

예제들은 스프링 3의 새로운 기능들에 맞춰서 개선되고 수정되었다. 추가로 예제 소스는 전용 SVN 저장소로 이동했다. 다음 링크에서 소스를 볼 수 있다.

https://anonsvn.springframework.org/svn/spring-samples/

그래서 예제들은 더는 스프링 3과 함께 배포지 않는다. 위의 저장소에서 따로 다운받아야 한다. 하지만 이 문서는 다양한 기능을 설명하기 위해 몇몇 예제들(특히 Petclinic)을 참조할 것이다.

Note
서브버전(SVN)에 대한 더 자세한 정보는 프로젝트 홈페이지를 참고해라. http://subversion.apache.org/

2.4 새로운 모듈 구조와 빌드 시스템
프레임워크 모듈을 수정했고 이제부터는 모듈 jar마다 하나의 소스트리로 분리해서 관리한다.

  • org.springframework.aop
  • org.springframework.beans
  • org.springframework.context
  • org.springframework.context.support
  • org.springframework.expression
  • org.springframework.instrument
  • org.springframework.jdbc
  • org.springframework.jms
  • org.springframework.orm
  • org.springframework.oxm
  • org.springframework.test
  • org.springframework.transaction
  • org.springframework.web
  • org.springframework.web.portlet
  • org.springframework.web.servlet
  • org.springframework.web.struts
스프링 웹 플로우(Web Flow) 2.0을 새로운 빌드시스템으로 사용한다. 웹 플로우는 다음과 같은 특징이 있다.
  • Ivy기반의 "Spring Build" 시스템
  • 일관된 배포과정
  • 일관된 의존성 관리
  • 일관된 OSGi manifest 생성
Note:
전체 프레임워크를 대부분 포함하고 있는 spring.jar artifact는 더는 제공하지 않는다.

2.5 새로운 기능
다음은 스프링 3.0의 새로운 기능들이다. 이번 장 후반부에서 각 기능의 세부사항을 살펴볼 것이다.

  • 스프링 표현언어(Expression Language)
  • IoC 개선/자바 기반의 빈(bean) 메타데이터
  • 범용적인 타입 컨버전 시스템과 필드 포매팅 시스템
  • 스프링 웹 서비스 프로젝트의 객체와 XML을 매핑하는 기능(OXM) 추가
  • 광범위한 REST 지원
  • @MVC 추가
  • 선언적인 모델 유효성 확인
  • Java EE 6에 대한 조기 지원
  • 데이터베이스 지원 내장

2.5.1 자바 5로 코어 API 개선
BeanFactory 인터페이스는 가능한 한 타입있는 빈(bean) 인스턴스를 돌려준다.

  • T getBean(Class<T> requiredType)
  • T getBean(String name, Class<T> requiredType)
  • Map<String, T> getBeansOfType(Class<T> type)
Spring의 TaskExecutor 인터페이스는 이제 java.util.concurrent.Executor를 상속받는다.
  • 상속받은 AsyncTaskExecutor는 표준 Callable와 Future를 지원한다.
자바 5기반의 새로운 변환 API와 SPI
  • 무상태 ConversionService와 Converters
  • 표준 JDK 프로퍼티 에디터는 필요 없어졌다.
타입이 있는 ApplicationListener<E>

2.5.2 스프링 표현 언어(Expression Language)
스프링은 표현언어를 도입했다. 스프링의 표현언어는 일반적인 EL과 문법상으로는 유사하지만 더 많은 기능을 제공한다. 표현언어는 XML이나 빈설정에 기반을 둔 어노테이션을 정의할 때 사용할 수 있다. 또한, 스프링 표현언어는 스프링의 모든 제품에 걸쳐 표현언어 지원의 근간이 된다. 새로운 기능의 세부사항은 스프링 표현언어 (SpEL). 챕터에서 설명한다.

스프링 커뮤니티에 단독으로 제공하기 위해 스프링 표현언어를 만들었고 스프링의 모든 제품군에서 사용할 수 있는 표현언어를 지원하려는 목적이었다. 스프링 제품군의 프로젝트에서 나온 요구사항으로 기반으로 기능을 만들었다. SpringSource Tool Suite 에 기반을 둔 이클립스에서 코드 자동완성에 대한 요구사항도 포함한다.

다음은 데이터베이스 설정의 프로퍼티 설정에서 표현언어를 어떻게 사용하는지를 보여주는 예제이다.



Xml
1
2
3
4
5
6
<bean class="mycompany.RewardsTestDatabase">
    <property name="databaseName"
        value="#{systemProperties.databaseName}"/>
    <property name="keyGenerator"
        value="#{strategyBean.databaseKeyGenerator}"/>
</bean>

이 기능은 어노테이션으로 컴포넌트를 설정할 때도 사용할 수 있다.


Java
1
2
3
4
5
6
7
8
9
@Repository 
public class RewardsTestDatabase {

    @Value("#{systemProperties.databaseName}")
    public void setDatabaseName(String dbName) {  }

    @Value("#{strategyBean.databaseKeyGenerator}")
    public void setKeyGenerator(KeyGenerator kg) {  }
}

2.5.3 제어의 역전 (IoC) 컨테이너
2.5.3.1 자바기반의 빈(bean) 메타데이터
JavaConfig 프로젝트의 몇몇 핵심 기능을 스프링 프레임워크에 추가했다. 이 말은 다음 어노테이션을 이제 직접 지원한다는 의미이다.

  • @Configuration
  • @Bean
  • @DependsOn
  • @Primary
  • @Lazy
  • @Import
  • @ImportResource
  • @Value
다음은 새로운 JavaConfig 기능을 사용해서 기본적인 설정을 제공하는 자바 클래스의 예제다.


Java
 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
32
33
package org.example.config;

@Configuration
public class AppConfig {
    private @Value("#{jdbcProperties.url}") String jdbcUrl;
    private @Value("#{jdbcProperties.username}") String username;
    private @Value("#{jdbcProperties.password}") String password;

    @Bean
    public FooService fooService() {
        return new FooServiceImpl(fooRepository());
    }

    @Bean
    public FooRepository fooRepository() {
        return new HibernateFooRepository(sessionFactory());
    }

    @Bean
    public SessionFactory sessionFactory() {
        // session factory 연결
        AnnotationSessionFactoryBean asFactoryBean = 
            new AnnotationSessionFactoryBean();
        asFactoryBean.setDataSource(dataSource());
        // 추가적인 설정
        return asFactoryBean.getObject();
    }

    @Bean
    public DataSource dataSource() { 
        return new DriverManagerDataSource(jdbcUrl, username, password);
    }
}

이 설정이 동작하게 하려면 어플리케이션 컨텍스트 XML 파일에 다음 컴포넌트 스캔을 추가해야 한다.

Xml
1
2
<context:component-scan base-package="org.example.config"/>
<util:properties id="jdbcProperties" location="classpath:org/example/config/jdbc.properties"/>

또는 AnnotationConfigApplicationContext를 직접 사용하는 @Configuration 클래스를 사용할 수 있다.

Java
1
2
3
4
5
public static void main(String[] args) {
    ApplicationContext ctx = new AnnotationConfigApplicationContext(AppConfig.class);
    FooService fooService = ctx.getBean(FooService.class);
    fooService.doStuff();
}

AnnotationConfigApplicationContext에 대한 전체 정보는 Section 4.12.2, “AnnotationConfigApplicationContext를 사용하는 스프링 컨테이너 예제 살펴보기”를 봐라.

2.5.3.2 컴포넌트안에서 빈(bean) 메타데이터 정의하기
@Bean 어노테이션을 사용한 메서드는 스프링 컴포넌트안에서도 사용할 수 있다. 이 메서드들은 컨테이너에 팩토리빈을 정의하는데 기여한다. 더 자세한 정보는 컴포넌트안에서 빈(bean) 메타데이터 정의하기를 참고해라.

2.5.4 범용적인 타입 컨버전 시스템과 필드 포매팅 시스템
범용적인 타입 컨버전 시스템을 도입했다. 타입 컨버전을 위해 SpEL로 타입 컨버전 시스템을 사용한다. 빈 프로퍼티 값에 바인딩할 때도 스프링 컨테이너와 DataBinder로 타입 컨버전 시스템을 사용할 수 있다.

추가로 필드값을 포매팅하기 위해 포매터 SPI를 도입하였다. 포매터 SPI는 스프링 MVC 같은 클라이언트 환경에서 사용하는 JavaBean PropertyEditor를 더 간단하고 튼튼하게 대체한다.

2.5.5 데이터 티어
스프링 웹 서비스 프로젝트의 객체와 XML을 매핑하는 기능 (OXM)은 스링 프레임워크의 코어로 이동했다. OXM기능은 org.springframework.oxm 패키지에 있다. OXM 모듈의 사용방법에 대한 더 자세한 내용은 O/X 매를 사용하는 XML 마샬링 챕터에서 설명한다.

2.5.6 웹 티어
웹 티어에서 가장 흥미로운 새 기능은 REST스러운 웹 서비스와 웹 어플리케이션 구축에 대한 지원이다. 어떤 웹 어플리케이션에서도 사용할 수 있는 새로운 어노테이션도 추가했다.

2.5.6.1 광범위한 REST 지원
기존에 존재하는 MVC 웹 프레임워크의 어노테이션을 확장해서 REST스러운 어플리케이션 구축에 대한 서버 측 지원을 추가했다. 클라이언트 측 지원은 JdbcTemplate나 JmsTemplate 같은 템플릿 클래스처럼 RestTemplate 클래스로 제공한다. 서버 측과 클라이언트 측 모두 REST기능은 HTTP 요청과 응답을 나타내는 객체의 변환을 위해 HttpConverter를 사용한다.


MarshallingHttpMessageConverter는 앞에서 이야기했던 개체를 XML로 매하는기능을 사용한다. 더 자세한 내용은 MVC와 RestTemplate을 참고해라.

2.5.6.2 @MVC 추가
스프링 MVC 설정을 엄청나게 간단하게 하는 mvc 네임스페이스를 도입했다.

@CookieValue와 @RequestHeaders같은 어노테이션을 추가했다. 더 자세한 내용은 @CookieValue 어노테이션으로 쿠키값 매핑하기과 @RequestHeader 어노테이션으로 요청 헤더 속성 매핑하기를 봐라.

2.5.7 선언적인 모델 유효성 확인
JSR 303을 포함해서 여러 가지 유효성 확인 지원이 개선되었고 기본 프로바이더로 Hibernate Validator를 사용한다.

2.5.8 Java EE 6에 대한 조기 지원
새로운 @Async 어노테이션(또는 EJB 3.1의 @Asynchronous 어노테이션)을 사용해서 비동기 메서드 호출을 지원한다.

JSR 303, JSF 2.0, JPA 2.0 등등

2.5.9 데이터베이스 지원 내장
HSQL, H2, Derby 같은 내장 자바 데이터베이스 엔진을 편리하게 지원한다.


[JAVA]1장 스프링 프레임워크 소개 #2..

출처 : Outsider's Dev Story https://blog.outsider.ne.kr/

이 포스팅은 다음의 스프링소스 라이센스를 따릅니다.

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

1.3 사용 시나리오
앞에서 설정한 블락을 만드는 것은 많은 시나리오에서 스프링이 논리적인 선택을 하도록 한다. 여기서 많은 시나리오는 애플릿부터 스프링의 트랜잭션 관리 기능과 웹 프레임워크 통합을 사용하는 완전한 엔터프라이즈 어플리케이션까지를 포함한다.

대표적인 완전한 형태의 스프링 웹 어플리케이션
대표적인 완전한 형태의 스프링 웹 어플리케이션

스프링의 선언적 트랜잭션 관리 기능은 웹 어플리케이션이 EJB 컨테이너가 관리하는 트랜잭션처럼 완전한 트랙잭션 기능을 가지게 한다. 모든 커스텀 비즈니스 로직은 간단한 POJO로 구현할 수 있고 스프링의 IoC 컨테이너로 관리할 수 있다. 추가적인 서비스는 이메일을 보내는 기능을 지원하고 어디서 유효성 확인 규칙을 실행할 것인지 선택하는 웹 계층과는 독립적인 유효성 확인에 대한 지원을 포함한다. 스프링의 ORM 지원은 JPA, Hibernate, JDO, iBatis와 통합되었다. 예를 들면 하이버네이트를 사용할 때 이미 존재하는 매핑 파일과 표준 하이버네이트 SessionFactory 설정을 계속 사용할 수 있다. 폼(Form) 컨트롤러는 도메인 모델에 대한 값으로 HTTP 파라미터를 전달하는 ActionForms나 다른 클래스에 대한 필요성을 제거함으로써 도메인 모델과 웹 계층을 자연스럽게 통합한다.

서드파티 웹 프레임워크를 사용하는 스프링 미들-티어
서드파티 웹 프레임워크를 사용하는 스프링 미들-티어

종종 다른 프레임워크로 완전히 전환하는 것이 어려울 수 있다. 스프링 프레임워크는 스프링 프레임워크안에서만 모든 일을 하도록 강제하지 않는다. 스프링 프레임워크는 스프링 프레임워크만 쓰던가 아예 쓰지 않던가 해야 하는 솔루션이 아니다. 이미 만들어진 프레임워크가 WebWork, Struts, Tapestry나 다른 UI 프레임워크로 만들어졌더라도 스프링의 트랜잭션 기능을 사용하는 스프링 기반의 미들-티어와 통합할 수 있다. 간단하게 ApplicationContext를 사용하는 비즈니스 로직을 연결하고 웹 계층과 통합하기 위해 WebApplicationContext 를 사용하면 된다.

원격 사용 시나리오
원격 사용 시나리오

이미 존재하는 코드에 웹서비스로 접근할 필요가 있으면 스프링의 Hessian-, Burlap-, Rmi-나 JaxRpcProxyFactory 클래스를 사용할 수 있다. 존재하는 어플리케이션으로의 원격접근을 허용하는 것은 어렵지 않다.

EJB - 존재하는 POJO의 랩핑(Wrapping)
EJB - 존재하는 POJO의 랩핑(Wrapping)

또 한, 스프링 프레임워크는 엔터프라이즈 자바빈, 존재하는 POJO의 재사용 허용, 선언적인 보안이 필요한 확장성 있고 안전한(fail-safe) 웹 어플리케이션에서 사용하는 무상태 세션빈을 감싸기 위해 접근과 추상화 계층을 제공한다.

1.3.1 의존성 관리와 작명 관례
의존성 관리과 의존성 주입은 다르다. 스프링의 좋은 기능(의존성 주입 같은)을 어플리케이션에서 사용하려면 필요한 모든 라이브러리(jar 파일)를 조립하고 런타임시에, 혹은 가능하다면 컴파일할 클래스패스에 둘 필요가 있다. 이러한 의존성은 주입되는 가상 컴포넌트가 아니라 (전통적으로) 파일시스템에 존재하는 물리적 리소스이다. 의존성 관리의 프로세스는 이러한 리소스를 필요한 위치에 두고 저장하고 클래스 패스에 추가하는 작업이 포함한다. 의존성은 직접적일 수도(예를 들어 런타임시에 스프링에 의존하는 어플리케이션) 간적접일 수도(예를 들어 commons-pool기반의 commons-dbcp에 의존하는 어플리케이션) 있다. 간적인 의존성은 보통 과도기적이라고 부르기도 하는데 이러한 의존성은 구별하고 관리하기가 몹시 어렵다.

스프링을 사용할 계획이라면 필요한 스프링 일부를 포함하는 jar 라이브러리의 복사본이 필요하다. 스프링은 의존성이 최대한 분리되도록 모듈이 패키징되어 있으므로 이 작업을 쉽게 할 수 있다. 예를 들어 웹 어플리케이션을 작성할 것이 아니라면 스프링-웹 모듈은 필요 없다. 이 가이드의 스프링 라이브러리 모듈을 참조하기 위해 spring-*나 spring-*.jar같은 짧은 작명 컨벤션을 사용한다. *은 모듈의 약칭을 의미한다. (예를 들어 spring-core, spring-webmvc, spring-jms등이다.) 실제 jar 파일명은 이 형식일 수도 있고(아래에서 볼 것이다) 아닐 수도 있으며 보통 파일명에 버전번호가 포함되어 있다.(예를 들면 spring-core-3.0.0.RELEASE.jar 와 같은 방식이다.)

보통 스프링은 결과물(Artifact)을 다음 네 곳에 배포한다.

  • 커뮤니티 다운로드 사이트 http://www.springsource.org/downloads/community 다운로드받기 쉽도록 zip 파일로 묶인 모든 스프링 jar파일이 있다. 3.0 버전부터 이곳의 jar파일명은 org.springframework.*-<version>.jar 의 형식을 따른다.
  • 메이븐 센트럴(Maven Central). 메이븐 센트럴은 메이븐의 기본 저장소이므로 사용하기 위해서 특별한 설정을 할 필요는 없다. 스프링이 의존하는 공통 라이브러리 중 다수는 메이븐 센트럴에서 이용할 수 있고 스프링 커뮤니티의 많은 부분은 의존성 관리에 메이븐을 사용하므로 편리하다. 메이븐 센트럴의 jar 파일명은 spring-*-<version>.jar의 형식을 따르고 메이븐 groupId는 org.springframework이다.
  • SpringSource에서 운영하는 Enterprise Bundle Repository (EBR). EBR는 스프링에 통합하는 모든 라이브러리를 제공한다. 모든 스프링 jar와 의존성 라이브러리를 포함해서 그 외 스프링으로 어플리케이션을 개발할 때 사용하는 공통 라이브러리에 대한 메이븐 저장소와 아이비(Iby) 저장소를 모두 이용할 수 있다. 릴리즈 버전과 마일스톤을 포함해서 개발 스냅샷까지 이곳에 배포된다. jar 파일명은 커뮤니티 다운로드와 같은 형식(org.springframework.*-<version>.jar )을 사용하고 외부 라이브러리(스프링소스가 만들지 않은)는 com.springsource 접두사가 있는 긴 형식이다. 더 자세한 정보는 FAQ를 참고해라.
  • 개발 스냅샵과 마일스톤 릴리즈를 위해 아마존 S2에서 운영되는 공개 메이븐 저장소를 사용한다.(최종 릴리즈의 복사본도 배포된다.) jar 파일명은 메이븐 센트럴과 같은 형식이므로 메이븐 센트럴에 배포된 다른 라이브러리와 함께 스프링의 개발 버전을 사용할 때 유용하다.

그래서 어떻게 의존성을 관리할 것인지를 먼저 결정해야 한다. 대부분은 메이븐이나 아이비같은 자동화된 시스템을 사용한다. 하지만 수동으로 모든 jar를 다운받아서 관리할 수도 있다. 메이븐이나 아이비로 스프링을 다운받으려면 어디서 다운받을 지를 결정해야 한다. 보통 OSGi를 고려한다면 Hibernate나 Freemarker같은 스프링 의존성의 OSGi 호환 결과물이 제공되는 EBR을 사용한다. OSGi를 쓸 계획이 없다면 저장소마다 장단점이 있지만, 어느 곳을 사용하던 큰 문제는 없다. 대신 섞어서 사용하지는 마라. EBR은 메이븐 센트럴과는 작명 관례를 사용하므로 특히 주의해야 한다.

Table 1.1. 메이븐 센트럴과 스프링소스 EBR 저장소의 비교

기능Maven CentralEBR
OSGi 호환명확하지 않음호환
Artifact의 수모든 종류로 수천 가지스프링 통합과 관련된 것들로 수백 가지
작명 관례의 일관성일관성 없음일관성 있음
GroupId의 작명 관례다양함. 새로운 artifact는 종종 도메인 명을 사용한다. 예를 들면 org.slf4j. 오래된 것들은 그냥 artifact명을 사용한다. 예를 들면 log4j출처나 메인 패키지 루트의 도메인명. 예를 들어 org.springframework
ArtifactId의 작명 관례다양함. 보통 프로젝트나 모듈명으로 구분자로 하이픈("-")을 사용한다. 예를 들면 spring-core, logj4메 인 패키지 루트에서 유래된 번들 심볼릭명. 예를 들면 org.springframework.beans. jar가 OSGi 호환성 패치가 되었다면 com.springsource가 추가된다. 예를 들면 com.springsource.org.apache.log4j
버전의 작명관례다 양함. 새로운 artifact는 m.m.m이나 m.m.m.X를 사용한다. (m은 숫자고 X는 문자다.) 오래된 artifact는 m.m을 사용하거나 아예 다른 방식을 사용한다. 순서는 정의되어 있지만, 종종 따르지 않는 경우도 있으므로 너무 신뢰하지 않는 것이 좋다.OSGi 버전번호인 m.m.m.X를 사용한다. 예를 들면 3.0.0.RC3. 텍스트는 숫처럼 버전의 순서가 지켜지는 알파벳만 사용할 수 있다.
배포보통 rsync나 소스제어 업데이트를 통해 자동으로 이루어진다. 프로젝트 저자는 JIRA로 각 jar를 업로드 할 수 있다.수동 (스프링소스가 처리하는 JIRA)
품질 보증정책에 의해서 이루어짐. 정확도에 대한 책임은 프로젝트 저자한테 있다.상세한 OSGi manifest, 메이븐 POM, 아이비 metadata를 따름. QA는 스프링 팀이 진행한다.
호스팅Contegix. Sonatyle이 여러 미러사이트를 함께 펀딩함.스프링 소스가 펀딩하는 S3.
검색 유틸리티다양함http://www.springsource.com/repository
스프링소스 도구의 통합메이븐 의존성 관리로 STS에 통합됨메이븐, Roo, 클라우드 파운드리와 함께 STS로 광범위하게 통합됨

1.3.1.1 스프링 의존성과 스프링에 기반하는 의존성
스프링이 엔터프라이즈와 다른 외부 도구들에 대한 광범위한 통합과 지원을 제공하더라도 의도적으로 의존성을 최소한으로 유지해야 한다. 간단한 사용을 위해서라면 많은 jar 라이브러리를 다운받아 설치하지 말아야 한다.(자동으로 한다고 하더라도) 기본적인 의존성 주입을 사용하려면 오직 하나의 외부 의존성만 필요하고 이는 로깅을 위한 것이다.(로깅 옵션에 대한 더 자세한 내용은 아래를 봐라.)

다음은 스프링에 의존하는 애플리케이션 설정하는 필요한 기본적인 과정을 설명할 차례다. 먼저 메이븐과 아이비를 사용한다. 모든 경우에서 명확한 것이 없다면 의존성 관리 시스템의 문서를 참고하거나 예제코드를 봐라. - 스프링은 개발과정에는 의존성 관리를 위해 아이비를 사용하고 예제는 대부분 메이븐을 사용한다.

1.3.1.2 메이븐 의존성 관리
메이븐으로 의존성을 관리한다면 로깅 의존성을 명시할 필요도 없다. 예를 들어 어플리케이션 컨텍스트을 생성하고 어플리케이션 설정에 의존성 주입을 사용하려면 메이븐 의존성은 다음과 같을 것이다.



Xml
1
2
3
4
5
6
7
8
<dependencies>
  <dependency>
     <groupId>org.springframework</groupId>
     <artifactId>spring-context</artifactId>
     <version>3.0.0.RELEASE</version>
     <scope>runtime</scope>
  </dependency>
</dependencies>

이것이 전부다. 스프링 API를 거슬러서 컴파일할 필요가 없다면 scope를 런타임으로 선언할 수 있다. 이는 기본적인 의존성 주입의 유즈케이스다.

위의 예제에서 메이븐 센트럴의 작명 관례를 사용했으므로 메이븐 센트럴이나 스프링소스의 S3 메이븐 저장소에서 동작한다. S3 메이븐 저장소를 사용하려면(예를 들어 마일스톤이나 개발 스냅샷을 사용하기 위해) 메이븐 설정에 저장소의 위치를 명시해야 한다. 전체 릴리즈를 사용하려면 다음과 같이 작성한다.



Xml
1
2
3
4
5
6
7
<repositories>
  <repository>
     <id>com.springsource.repository.maven.release</id>
     <url>http://maven.springframework.org/release/</url>
     <snapshots><enabled>false</enabled></snapshots>
  </repository>
</repositories>

마일스톤을 사용하려면 다음과 같이 작성한다.

Xml
1
2
3
4
5
6
7
<repositories>
  <repository>
     <id>com.springsource.repository.maven.milestone</id>
     <url>http://maven.springframework.org/milestone/</url>
     <snapshots><enabled>false</enabled></snapshots>
  </repository>
</repositories>

개발 스냅샷을 사용하려면 다음과 같이 작성한다.

Xml
1
2
3
4
5
6
7
<repositories>
  <repository>
     <id>com.springsource.repository.maven.snapshot</id>
     <url>http://maven.springframework.org/snapshot/</url>
     <snapshots><enabled>true</enabled></snapshots>
  </repository>
</repositories>

스프링소스의 EBR을 사용하려면 의존성에 대해서 앞에서와는 다른 작명 관례를 사용해야 한다. 이름은 예하기 쉽다. 예를 들면 다음과 같다.

Xml
1
2
3
4
5
6
7
8
<dependencies>
  <dependency>
     <groupId>org.springframework</groupId>
     <artifactId>org.springframework.context</artifactId>
     <version>3.0.0.RELEASE</version>
     <scope>runtime</scope>
  </dependency>
</dependencies>

저장소의 위치도 명시적으로 선언해야 한다.(URL부분만 중요하다)

Xml
1
2
3
4
5
6
<repositories>
  <repository>
     <id>com.springsource.repository.bundles.release</id>
     <url>http://repository.springsource.com/maven/bundles/release/</url>
  </repository>
</repositories>

직접 의존성을 관리한다면 위에서 선언한 저장소 URL은 검색하기에 좋지 않다. 하지만 http://www.springsource.com/repository에서 의존성을 검색하고 다운로드 받을 수 있는 화면을 제공한다. 메이븐이나 아이비를 사용한다면 쉽게 복사해서 붙일 수 있도록 메이븐과 아이비 설정 스니펫을 제공한다.

1.3.1.3 아이비(Ivy) 의존성 관리
의존성 관리를 Ivy로 하길 좋아하더라도 라이브러리 이름과 설정옵션은 비슷하다.

아이비를 설정하려면 ivysettings.xml에 스프링소스 EBR을 나타내는 다음 resolver를 추가한다.



Xml
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
<resolvers>
  
  <url name="com.springsource.repository.bundles.release">

   <ivy pattern="http://repository.springsource.com/ivy/bundles/release/[organisation]/[module]/[revision]/[artifact]-[revision].[ext]" />
   <artifact pattern="http://repository.springsource.com/ivy/bundles/release/[organisation]/[module]/[revision]/[artifact]-[revision].[ext]" />

  </url>

  <url name="com.springsource.repository.bundles.external">

   <ivy pattern="http://repository.springsource.com/ivy/bundles/external/[organisation]/[module]/[revision]/[artifact]-[revision].[ext]" />
   <artifact pattern="http://repository.springsource.com/ivy/bundles/external/[organisation]/[module]/[revision]/[artifact]-[revision].[ext]" /> 

  </url>

</resolvers>

위의 XML은 라인이 너무 길어서 유효한 XML이 아니다. - 복사해서 붙다면 URL 가운데 줄 바꿈을 삭제해라

아이비가 EBR로 설정되면 의존성 추가는 쉽다. 저장소 검색페이지에서 원하는 라이브러리의 상세페이지에 들어가서 의존성 부분에 추가할 아이비 스니펫을 찾을 수 있다. 예를 들어 ivy.xml에 다음과 같이 추가한다.



Xml
<dependency org="org.springframework" 
name="org.springframework.core" rev="3.0.0.RELEASE" 
conf="compile->runtime"/>

1.3.2 로깅
스프링에서 로깅은 아주 중요한 의존성이다. 


그 이유는
a) 로깅은 유일하게 강제적인 외부 의존성이고, 
b) 개발자는 사용하는 도구에서 어떤 출력을 보기 원하고 
c) 스프링은 로깅 의존성의 선택이 있는 다른 많은 툴과 통합되기 때문이다. 

어플리케이션 개발자의 목표 중 하나는 외부 컴포넌트를 포함한 전체 어플리케이션의 중심에서 통일된 로깅을 설정하는 것이다. 이는 로깅 프레임워크가 많이 존재하기 때문에 쉽지 않다.

스프링의 강제적인 로깅 의존성은 Jakarta Commons Logging API (JCL)이다. JCL을 컴파일하고 스프링 프레임워크를 상속받은 클래스에서 사용할 수 있는 Log객체로 만든다. 이는 같은 로깅 라이브러리를 사용하는 모든 버전의 스프링 사용자에게 중요하다. 스프링은 스프링을 상속받은 어플리케이션에서조차 하위호환성이 유지되므로 마이그레이션이 쉽다. 마이그레이션을 하는 방법은 스프링의 모듈 중 하나를 명시적으로 commons-logging(JCL의 정식 구현체)에 의존하게 하고 다른 모듈은 컴파일 시에 의존하게 하는 것이다. 예를 들어 메이븐을 사용하는데 commons-logging의 의존성이 어디에 있는지 모른다면 스프링의 핵심모듈인 spring-core에 있다.

commons-logging의 좋은 점은 당신이 어플리케이션을 동작하게 하는 것에만 신경 쓰면 된다는 것이다. commons-logging에는 잘 알려진 클래스패스나 적절한 위치(필요하다면 지적할 수 있다.)에서 다른 로깅 프레임워크를 찾는 런타임 디스커버리 알고리즘이 있다. 이용할 수 있는 로깅 프레임워크가 없다면 JDK(정확히는 java.util.logging이나 JUL이다.)로 꽤 괜찮은 로그를 남긴다. 대부분 상황에서 로그가 잘 나오는 것을 확인해서 스프링이 잘 동작한다는 것을 알 수 있다. 이는 중요하다.

1.3.2.1 Commons Logging 사용하지 않기
안타깝게도 commons-logging의 런타임 디스커버리 알고리즘은 엔드유저에게는 편리하지만, 문제의 소지가 있다. 시간을 거꾸로 돌릴 수 있거나 스프링을 새로운 프로젝트로 다시 시작한다면 런타임 디스커버리 알고리즘은 다른 로깅 의존성을 사용할 것이다. 첫 번째 선택은 아마 Simple Logging Facade for Java (SLF4J)일 것이다. 어플리케이션에서 스프링과 함께 사용하는 많은 툴은 SLF4J를 사용한다.

commons-logging는 쉽게 사용하지 않게 할 수 있다. 그냥 런타임시에 클래스패스에 존재하지 않으면 된다. 스프링 의존성이 선언되어 있으므로 메이븐에서 의존성을 제외 처리하면 된다.



Xml
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
<dependencies>
  <dependency>
     <groupId>org.springframework</groupId>
     <artifactId>spring-context</artifactId>
     <version>3.0.0.RELEASE</version>
     <scope>runtime</scope>
     <exclusions>
        <exclusion>
           <groupId>commons-logging</groupId>
           <artifactId>commons-logging</artifactId>
        </exclusion>
     </exclusions>
  </dependency>
</dependencies>

위 코드를 추가하면 어플리케이션의 빌드가 깨질 것이다. 클래스패스에 JCL API의 구현체가 없기 때문이다. 새로운 구현체를 추가하면 이 문제를 해결할 수 있다. 다음 섹션에서 예제를 통해 SLF4J를 사용하는 JCL 구현체를 새로 추가하는 방법을 살펴볼 것이다.

1.3.2.2 SLF4J의 사용
SLF4J는 의존성이 깔끔하고 commons-logging보다 런타임에서 더 효율적이다. 다른 로깅 프레임워크의 런타임 디스커버리 대신 컴파일할 때 바인딩하기 때문이다. 이는 런타임에서 벌어질 일을 더 명시적으로 지정해야 한다는 의미이다. 따라서 의존성을 선언하고 적절하게 설정해야 한다. SLF4J는 대부분의 로깅 프레임워크에 대한 바인딩을 지원하므로 기존에 사용하던 로깅 프레임워크를 계속 사용할 수 있다. 사용하는 로깅 프레임워크를 설정과 관리에 바인딩하면 된다.

SLF4J는 JCL을 포함한 많은 로깅 프레임워크에 대한 바인딩을 지원한다. 반대로 다른 로깅 프레임워크가 SLF4J로 바인딩할 수도 있다. 즉 다른 로깅프레임워크와 SLF4J사이에 브릿지로 사용할 수도 있다. 그래서 스프링과 SLF4J를 함께 사용하려면 commons-logging의존성을 SLF4J-JCL 브릿지로 바꿔야 한다. 설정을 바꾸었으면 스프링에서 호출된 로깅은 SLF4J API를 호출하는 로깅으로 전환된다. 그래서 어플리케이션의 다른 라이브러리가 같은 API의 로깅을 사용한다면 한 곳에서 로깅을 설정하고 관리할 수 있다.

스프링을 SLF4J로 브릿지하고 명시적으로 SLF4J를 Log4J로 바인딩하는 것이 가장 일반적이다. 브릿지, SLF4J API, Log4J로의 바인딩, Log4J구현체의 4가지 의존성을 추가해야 한다.(commons-logging는 제외 처리해야 한다.) 메이븐이라면 다음과 같이 추가한다.



Xml
 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
32
33
34
35
36
37
38
<dependencies>
  <dependency>
     <groupId>org.springframework</groupId>
     <artifactId>spring-context</artifactId>
     <version>3.0.0.RELEASE</version>
     <scope>runtime</scope>
     <exclusions>
        <exclusion>
           <groupId>commons-logging</groupId>
           <artifactId>commons-logging</artifactId>
        </exclusion>
     </exclusions>
  </dependency>
  <dependency>
     <groupId>org.slf4j</groupId>
     <artifactId>jcl-over-slf4j</artifactId>
     <version>1.5.8</version>
     <scope>runtime</scope>
  </dependency>
  <dependency>
     <groupId>org.slf4j</groupId>
     <artifactId>slf4j-api</artifactId>
     <version>1.5.8</version>
     <scope>runtime</scope>
  </dependency>
  <dependency>
     <groupId>org.slf4j</groupId>
     <artifactId>slf4j-log4j12</artifactId>
     <version>1.5.8</version>
     <scope>runtime</scope>
  </dependency>
  <dependency>
     <groupId>log4j</groupId>
     <artifactId>log4j</artifactId>
     <version>1.2.14</version>
     <scope>runtime</scope>
  </dependency>
</dependencies>

단순히 로깅을 사용하기 위해 너무 많은 의존성을 추가한 것처럼 보일 수 있다. 하지만 이는 선택사항이고 평범한 commons-logging보다 나은 동작을 한다. 특히 commons-logging는 OSGi 플랫폼 같은 엄격한 컨테이너를 사용한다면 클래스로더 이슈도 고려해야 한다. 또한, 바인딩이 런타임이 아닌 컴파일타임에 이뤄지기 때문에 성능적인 이점도 있다고 알려졌다.

더 적은 과정과 의존성을 사용하는 SLF4J 사용자들은 보통 Logback로 직접 바인딩한다. Logback은 SLF4J를 직접 구현했기 때문에 추가적인 바인딩 과정을 줄여준다. 그래서 4개가 아닌 2개의 라이브러리에만 의존할 수 있다.(jcl-over-slf4j와 logback) Logback으로 직접 바인딩하는 방법을 사용했다면 (스프링이 아닌) 다른 외부 의존성에서 slf4j-api에 대한 의존성을 제외처리 해야 한다. 이는 클래스패스에 오직 한가지 버전의 API만 존재하기를 바라기 때문이다.

1.3.2.3 Log4J의 사용
많은 사람들이 설정과 관리 때문에 로깅 프레임워크로 Log4j를 사용한다. Log4j는 사용하기 편하고 잘 구성되어 있다. 사실 스프링을 만들고 테스트할 때 런타임에서 Log4j를 사용했다. 스프링은 Log4j의 설정과 초기화를 위한 몇 가지 유틸리티도 제공한다. 그래서 스프링의 몇몇 모듈에는 Log4j에 대한 의존성이 컴파일타임에 선택적으로 의존성이 존재한다.

기본 JCL 의존성(commons-logging)과 함께 Log4j가 동작하게 하려면 클래스패스에 Log4j를 두고 클래스패스의 루트에 설정파일 (log4j.properties나 log4j.xml)을 두면 된다. 메이븐 사용자라면 의존성 선언에 추가한다.



Xml
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
<dependencies>
  <dependency>
     <groupId>org.springframework</groupId>
     <artifactId>spring-context</artifactId>
     <version>3.0.0.RELEASE</version>
     <scope>runtime</scope>
  </dependency>
  <dependency>
     <groupId>log4j</groupId>
     <artifactId>log4j</artifactId>
     <version>1.2.14</version>
     <scope>runtime</scope>
  </dependency>
</dependencies> 

다음은 콘솔에 로그를 출력하는 log4j.properties의 예제이다.

Xml
log4j.rootCategory=INFO, stdout

log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%d{ABSOLUTE} %5p %t %c{2}:%L - %m%n

log4j.category.org.springframework.beans.factory=DEBUG

네이티브 JCL를 사용하는 런타임 컨테이너
많은 사람들이 JCL의 구현체를 제공하는 컨테이너에서 스프링 어플리케이션을 구동한다. IBM 웹스피어(Websphere) 어플리케이션 서버(WAS)가 대표적이다. 웹스피어는 종종 문제를 일으키는데 불행히도 거기에는 완벽한 해결책이 없다. 대부분의 상황에서 단순히 어플리케이션에서 commons-logging를 제외 처리하는 것으로는 해결되지 않는다.

이 문제를 좀 더 명확히 보자. 알려진 문제점은 JCL이나 commons-logging자체의 문제는 아니다. 더 정확히 말하면 commons-logging를 다른 프레임워크(대개 Log4J)로 바인딩해서 발생한 문제다. 바인딩이 실패하는 이유는 몇몇 컨테이너가 사용하는 commons-logging의 과거 버전(1.0)과 대부분이 사용하는 최신 버전(1.1)사이에서 런타임 디스커버리 방법이 달라졌기 때문이다. 스프링은 JCL API에서 특이한 API는 전혀 사용하지 않으므로 문제가 발생하지 않는다. 하지만 스프링이나 어플리케이션이 로깅을 시도하자마자 Log4J로의 바인딩이 동작하지 않는 것을 발견할 수 있을 것이다.

WAS에서 이러한 상황을 겪을 가장 쉬운 해결책은 컨테이너 대신 어플리케이션이 JCL 의존성을 제어하도록 클래스 로더의 계층을 거꾸로 하는 것이다.(IBM은 이를 "parent last"라고 부른다.) 이 옵션은 항상 열려 있는 것은 아니지만, 대안적인 방법을 위한 공개된 영역에서 다수의 다른 제안이 존재한다. 아마 컨테이너의 정확한 버전과 기능에 의존하도록 바꿀 것이다.