Whiteship's Note


스프링 3.0의 설정 간편화

Spring/etc : 2009.12.23 11:15


원문: http://blog.springsource.com/2009/12/22/configuration-simplifications-in-spring-3-0/

케이스가 시작한 "스프링 3 간편화" 시리즈 두번째로 스프링의 새로운 @Configuration 애노테이션 및 그와 관련된 지원 기능을 매우 간략하게 소개하고자 한다.

스프링 JavaConfig 프로젝트에 관심을 가지고 있던 사람들이라면 @Configuration 애노테이션 클래스가 스프링 XML 파일과 매우 비슷한 역할을 한다는 것을 알 것이다. 메서드와 애노테이션을 사용하여 스프링 빈을 정의를 선언하는 코드-중심적인 방법을 제공한다. 이러한 것을 POC(Plain Old Configruation)이라고 부를 수도 있겠다. :) XML이 하나도 필요없는 간단한 상활을 일컷는 말이다.

시작해보자. @Configuration 기능을 설명하려고 새로운 스프링 샘플 SVN 저장소에 매우 간단한 프로젝트를 만들어두었다. 그것을 받아서 바로 빌드하고 싶을것이다. 서브버전 클라이언트와 최신 버전 메이븐이 필요하다.

svn co https://src.springframework.org/svn/spring-samples/configuration-basic/trunk configuration-basic
cd configuration-basic
mvn clean test
[...]
Tests run: 1, Failures: 0, Errors: 0, Skipped: 0

[INFO] ————————————————————————
[INFO] BUILD SUCCESSFUL
[INFO] ————————————————————————

이클립스 .classpath와 .project 메타데이터도 체크아웃에 포함되어 있기 때문에 프로젝트를 SpringSprout Tool Suite 또는 m2eclipse 플러그인을 설치한 최신버전 이클립스에서 import 할 수 있을 것이다. 두 경우 모두 File -> Import -> Existing Projects into Workspace를 하면 된다.

AppConfig.java 클래스부터 살펴보자. @Configuration 애노테이션을 추가한 클래스는 XML 설정 기반 스프링 애플리케이션의 app-config.xml과 같은 역할을 한다. 실행시점에 어떻게 객체 인스턴스들이 연관되어 있으며 관리되는지에 대한 "청사진"을 제공하기 때문에 프로젝트를 살펴보기 좋은 시작점이 된다.

@Configuration
public class AppConfig {

    public @Bean TransferService transferService() {
        return new TransferServiceImpl(accountRepository());
    }

    public @Bean AccountRepository accountRepository() {
        return new InMemoryAccountRepository();
    }

}

Granted, 이 예제는 진짜 JDBC Datasource를 사용하지도 않는 매우 간단한 애플리케이션이다. 하지만 이 글의 목적은 기본 개념을 제공하는 것이기 때문에 괜찮다. @Bean을 선언한 메서드는 실행 시점에 스프링 컨테이너에의해 호출되며 반환되는 객체를 스프링 컨테이너가 다른 빈들처럼 관리한다. 다른 빈과의 의존성은 간단하게 다른 빈 메서드를 호출하는 것으로 표현할 수 있다. TransferServiceImpl은 AccountRepository를 생성자 인자로 필요로 하기 때문에 간단하게 accountRepository() 메서드를 호출했다.

경험많은 스프링 사용자라면 이 예제를 보고 "빈 스코프는 어떻게 되는가?"라고 질문할 것이다. 좋은 질문이다. 아시다시피 모든 스프링 빈은 스코프를 가지고 있다. 기본으로 빈의 스코프는 '싱글톤'이며 이것은 스프링 컨테이너 당 하나의 빈 인스턴스만 사용된다는 것을 의미한다. 위의 코드를 보면 accountRepository()를 여러번 호출할 때마다 여러 인스턴스를 만들것 처럼 보이지만 실제로 그렇지는 않다! @Configuration 클래스가 실행 시점에 처리되면 동적으로 (CGLIB을 사용하여) 그 하위 클래스를 만들고, 그 하위 클래스의 @Bean 메서드들은 스코프 개념을 보장하도록 코드를 조작한다.

보시다시피, @Bean 메서드를 정의하는 것은 매우 간단하다. 이제 컨테이너를 동작시키고 저 객체들을 사용해보자.

TransferServiceTest JUnit 시스템 테스트와 transfer100Dollars() @Test 메서드를 보자. 가장 먼저 눈에띄는 것은 AnnotationConfigApplicationContext 사용일 것이다. 이것은 새로운 ApplicationContext 구현체로 @Configuration 클래스를 직접 사용하여 스프링 컨테이너 생성을 지원하도록 스프링 3에 추가되었다. 이 컨텍스트는 AppConfig.class를 생성자 매개변수로 사용하며, 그런다음 TransferService와 AccountRepository 타입의 빈을 getBaen(Class) 메서드를 이용하여 가져온다. 메서드의 남은 부분은 일반적인 JUnit 검증 과정으로 TransferService와 AccountRepository API를 확인하고 예상한대로 잘 동작하는지 확인한다.

public class TransferServiceTest {

    @Test
    public void transfer100Dollars() {
        // create the spring container using the AppConfig @Configuration class
        ApplicationContext ctx = new AnnotationConfigApplicationContext(AppConfig.class);

        // retrieve the beans we'll use during testing
        AccountRepository accountRepository = ctx.getBean(AccountRepository.class);
        TransferService transferService = ctx.getBean(TransferService.class);

        // create accounts to test against
        accountRepository.add(new Account("A123", 1000.00));
        accountRepository.add(new Account("C456", 0.00));

        // check account balances before transfer
        assertThat(accountRepository.findById("A123").getBalance(), equalTo(1000.00));
        assertThat(accountRepository.findById("C456").getBalance(), equalTo(0.00));

        // perform transfer
        transferService.transfer(100.00, "A123", "C456");

        // check account balances after transfer
        assertThat(accountRepository.findById("A123").getBalance(), equalTo(900.00));
        assertThat(accountRepository.findById("C456").getBalance(), equalTo(100.00));
    }

}

바로 이거다! 간단하고, 순수한 자바이고(사실 저는 개인적으로 이부분에 대해서는 약간의 이견을 가지고 있지만;;), 타입-안정적인 설정이다. 이것이 스프링의 핵심 의존성 주입 기능의 편리하고 강력한 추가기능임을 알았으면 좋겠다.

물론, 오늘 여기서는 매우 간략하게 살펴봤다. @Configuration 클래스로 더 많은 것을 할 수 있으며 자세한 기능은 다음 글에서 설명하도록 하겠다. 하지만 날 기다리지말고 스스로 스프링 3 레퍼런스 문서의 @Configuration 부분을 읽어보길 바란다. 이 예제 프로젝트를 시작점으로 빠르게 새로운 기능의 나머지 부분을 확읺보기 바란다.

피드백을 기대한다. @Configuration과 모든 새로운 스프링 3 기능을 즐기기 바란다. 즐거운 연휴 되시길!

* Thanks to Erich Eichinger for (half-jokingly) coining the phrase 'Plain Old Configuration'. You can take a look at the work he and the Spring.NET team are doing with their similar 'CodeConfig' project here.

ps: 이번글에도 링크가 굉장히 많은데;; 귀찮아서 생략했습니다. 언젠가 안 귀찮을 때 수정하겠습니다.
top


스프링 3.0의 MVC 간편화

Spring/3.0 : 2009.12.22 11:42


원문: http://blog.springsource.com/2009/12/21/mvc-simplifications-in-spring-3-0/
봄싹위키: http://springsprout.org/wiki/1556.do

유겐아렌이 언급했듯이, 모든 자바 개발자는 부담없이 스프링 3.0으로 버전을 올릴 수 있다. 이제 스프링 3이 나왔고 나는 여러분이 아직 모르고 있을 법한 MVC 기능을 소개하고자 한다. 이 기능들이 여러분에게 유용하고 웹 애플리케이션 개발을 빠르게 시작하는데 도움이 되기를 바란다.

또한 이 글은 "스프링 3 간편화" 시리즈의 시작으로 앞으로 몇일 또는 몇주 동안 이와 비슷한 글들이 올라올 것으로 예상한다.

설정 간편화

스프링 3은 mvc 네임스페이스를 도입하여 스프링 MVC 설정을 대폭 간편화했다. 지금까지 다른 개선사항들은 스프링 MVC 애플리케이션을 구성하고 실행하는것을 간편화 시켜주지는 않았다. mvc-basic 예제를 통해 살펴보도록 하자.

mvc-basic 예제는 스프링 MVC 기능의 기본 구성을 보여주도록 만들었다. 프로젝트는 spring-samples SVN 저장소에서 얻을 수 있으며 메이븐으로 빌드하고 이클립스로 import할 수 있다. web.xml 부터 시작하여 거기에 있는 설정부터 살펴보자. 주목할 것은 DispatcherServlet이 단일 마스터 스프링 설정 파일로 설정되어 있고 그 안에서 모든 애플리케이션 구성요소를 초기화한다. URL Rewrite를 설정하여 모든 요청을 깔끔하고 REST-스러운 URL로 DispatcherServlet에 보낸다.

마스터 설정 app-config.xml에서 일반적인 구성을 살펴볼 수 있다. 컴포넌트 스캔으로 클래스패스에서 애플리케이션 구성요소를 찾는다. MessageSource를 설정하여 지역화된 리소스 번들을 설정한다. 마지막으로 애플리케이션의 스프링 MVC 설정을 import한다.

mvc-config.xml 안에서 스프링 3의 첫번째 새 기능을 볼 수 있다.

<!-- Configures the @Controller programming model -->
<mvc:annotation-driven />

이 태그는 요청을 @Controller로 디스패치할 때 필요한 HadlerMapping과 HandlerAdapter를 등록한다. 또한 클래스패스에 무엇이 있는지에 따른 감각적인 기본값(sensible defaults)을 제공한다. 그러한 기본값은 다음과 같다.

- 자바빈 PropertyEditor 보다 더 견고한 대체제인 스프링 3 타입 ConversionService 사용하기
- @NumberFormat으로 숫자 필드 포매팅 지원
- @DateTimeFormat을 사용하여 Date, Calendar 포매팅 지원. Joda Time이 클래스패스에 있다면 Joda Time도 포매팅 지원.
- JSR-303 공급자가 클래스패스에 있다면 @Controller 입력값을 @Valid를 사용하여 검증
- JAXB가 클래스패스에 있다면 XML 읽기/쓰기 지원
- Jackson이 클래스패스에 있다면 JSON 읽기/쓰기 지원

꽤 멋지지 않은가? 훗

계속해서 mvc-config.xml 다음 줄에서 또다른 새로운 기능을 살펴보자.

<!-- Forwards requests to the "/" resource to the "welcome" view -->
<mvc:view-controller path="/" view-name="welcome" />

mvc:view-controller는 랜더링할 뷰를 선택하는 ParameterizableViewController를 등록한다. "/"를 요청하면 welcome 뷰를 랜더링하도록 설정했다. 실제 뷰 템플릿은 /WEB-INF/views 디렉토리의 .jsp가 랜더링 된다.

계속해서 mvc-config에서 살펴보지 않은 새로운 기능을 보도록 하자.

<!-- Configures Handler Interceptors -->
<mvc:interceptors>
    <!-- Changes the locale when a 'locale' request parameter is sent; e.g. /?locale=de -->
    <bean class="org.springframework.web.servlet.i18n.LocaleChangeInterceptor" />
</mvc:interceptors>

mvc:interceptors 태그는 모든 컨트롤러에 적용할 HandlerInterceptor를 등록하게 해준다. 이전에는 반복적으로 모든 HandlerMapping 빈에 interceptor들을 등록했었다. 또한 이 태그를 사용하여 인터셉터를 적용할 URL 경로를 제한할 수 있다.

자 지금까지 살펴본 것을 종합하여, 예제를 배포하면 다음과 같은 welcome 뷰가 랜더링 될 것이다.


다른 지역 링크를 클릭하여 LocaleChangeInterceptor가 사용자 지역을 교체하도록 해보자.

데이터 바인딩 간편화

다음으로 설명할 새 기능은 @Controller 바인딩과 검증이다. 몇주 전에 글을 올렸다시피 이 부분에 새로운 기능이 많이 있다.

예제에서, @Controller Example 링크를 클릭하면 다음과 같은 폼이 랜더링 된다.


이 폼은 지역 정보 변경에 따라 국체화 필드 포매팅이 적용된다. 예를 들어, en에서 de로 바꾸면 날짜 형식을 12/21/10에서 12.12.10으로 바꾼다. 이런 동작과 폼 검증 규칙은 모델 애노테이션을 기반으로 한다.

public class Account {

    @NotNull
    @Size(min=1, max=25)
    private String name;

    @NotNull
    @NumberFormat(style=Style.CURRENCY)
    private BigDecimal balance = new BigDecimal("1000");

    @NotNull
    @NumberFormat(style=Style.PERCENT)
    private BigDecimal equityAllocation = new BigDecimal(".60");

    @DateTimeFormat(style="S-")
    @Future
    private Date renewalDate = new Date(new Date().getTime() + 31536000000L);

}

폼 서브밋은 다음의 AccountController 메서드가 처리한다.

@RequestMapping(method=RequestMethod.POST)
public String create(@Valid Account account, BindingResult result) {
    if (result.hasErrors()) {
        return "account/createForm";
    }
    this.accounts.put(account.assignId(), account);
    return "redirect:/account/" + account.getId();
}

이 메소드는 바인딩과 검증 작업 이후에 호출되며, Account 검증은 @Valid 애노테이션에 의해 수행된다. 만약 어떠한 검증 에러라도 존재한다면 createForm을 다시 랜더링 한다. 그렇지 않을 경우 Account는 저장되고 사용자는 http://localhost:8080/mvc-basic/account/1로 리다이렉트 된다.

또 다른 멋진 기능을 사용해보려면 /account/99 같이 존재하지 않는 계정을 요청해보기 바란다.

요약

스프링 3은 다양한 새 기능과 여러 기존 분야에 대한 간편화를 제공한다. 이 글을 통해 여러분에게 유용한 새로운 스프링 MVC 개선 사항들을 파악했기를 바란다. 맨 처음에 언급했듯이 더 많은 "스프링 3 간편화" 시리즈를 통해 계속해서 스프링 최신 버전의 새롭고 흥미로운 기능들을 소개할테니 기대하기 바란다.

즐거운 연휴되시길!

top


스프링의 로깅 의존성

Spring/etc : 2009.12.08 17:56


원문: http://blog.springsource.com/2009/12/04/logging-dependencies-in-spring/

봄싹 위키: http://springsprout.org/wiki/1439.do

이 글은 스프링이 결정한 선택 사항들과 개발자들이 스프링을 사용하여 애플리케이션을 만들 때 로깅으로 이용할 수 있는 옵션을 다룬다. 무언가를 많이 변경했기 때문이 아니라, 여러분이 애플리케이션에서 로깅을 구현하고 설정할 때 정보에 근거할 수 있도록 이제는 출시가 임박한 스프링 3.0을 따라야 할 시점이다. 먼저 스프링에 어떤 필수 의존성이 있는지 살펴본 다음, common logging 라이브러리 예제를 사용하여 애플리케이션에 로깅을 설정하는 방법을 좀 더 자세히 살펴보겠다. 예를 들어 메이븐 중앙 스타일 구성물 작명 규약을 사용하는 의존성 설정을 보여주겟다.

스프링 의존성과 스프링에 의존하는 것들

스프링은 광범위한 엔터프라이즈 및 여러 외부 도구를에 대한 연동과 지원을 제공하지만, 내부적으로 필수 의존성을 최소한으로 유지한다. 간단한 경우에 스프링을 사용할 때는 많은 수의 라이브러리를 다운로드(혹은 자동으로) 받을 필요가 없다. 기본적인 의존성 주입은 오직 하나의 외부 의존성을 필요로 하며, 그건 바로 로깅이다.(로깅 옵션에 대해서는 아래의 보다 자세한 설명을 참조하자.) 만약 의존성 관리를 메이븐으로 하고 있다면 로깅 의존성을 명시적으로 설정할 필요도 없다. 예를 들어, 애플리케이션 컨텍트를 만들고 의존성 주입을 이용하고 있다면 애플리케이션에 다음과 같이 설정하기만 하면 된다. 메이븐 의존성은 다음과 같을 것이다.

<dependencies>
   <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-context</artifactId>
      <version>3.0.0.RELEASE</version>
      <scope>runtime</scope>
   </dependency>
</dependencies>

이게 전부다. 기본적인 의존성 주입을 사용하는 경우처럼, 일반저긍로 스프링 API를 컴파일 할 필요가 없다면 scope가 runtime으로 설정해도 된다는 것에 주목하자.

위 예제에서 메이븐 중앙 작명 규약을 사용했기 때문에, 메이븐 중앙 또는 스프링소스 S3 메이븐 저장소와 잘 동작한다. S3 메이븐 저장소를 이용하려면(마일스톤 또는 개발자 스냅샷 버전을 사용하기 위해), 저장소 위치를 메이븐 설정 파일에 명시해야 한다. 전체 배포는 저장소는 다음과 같다.

<repositories>
   <repository>
      <id>com.springsource.repository.maven.release</id>
      <url>http://s3.amazonaws.com/maven.springsource.com/release/</url>
      <snapshots><enabled>false</enabled></snapshots>
   </repository>
</repositories>

마일스톤 저장소는 다음과 같다.

<repositories>
   <repository>
      <id>com.springsource.repository.maven.milestone</id>
      <url>http://s3.amazonaws.com/maven.springsource.com/milestone/</url>
      <snapshots><enabled>false</enabled></snapshots>
   </repository>
</repositories>

스냅샷은 저장소는 다음과 같다.

<repositories>
   <repository>
      <id>com.springsource.repository.maven.snapshot</id>
      <url>http://s3.amazonaws.com/maven.springsource.com/snapshot/</url>
      <snapshots><enabled>true</enabled></snapshots>
   </repository>
</repositories>

스프링소스 EBR을 사요하려면 의존성을 나타낼 때 다른 이름 규약을 사용해야 한다. 이름은 보통 유추하기 쉽다. 예를 들어 이번 경우에는 다음과 같다.

<dependencies>
   <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>org.springframework.context</artifactId>
      <version>3.0.0.RELEASE</version>
      <scope>runtime</scope>
   </dependency>
</dependencies>

물론 저장소도 명시적으로 설정해 줘야 한다.

<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에 사용자 인터페이스가 있으니 검색하여 의존성을 다운 받을 수 있다. 또한 이 사이트에는 간편한 메이븐과 Ivy 설정이 있으니 복사하여 붙여넣기로 쉽게 해당 도구에서 사용할 수 있다.

만약 Ivy를 사용하여 의존성 관리하는 것을 선호한다면 위와 비슷한 이름과 설정 옵션이 관리 시스템에 있거나 예제 코드를 살펴보기 바란다.

로깅

로깅은 매우 중요한 스프링 의존성이다. 왜냐하면 a) 유일한 외부 의존성이자, b) 모두가 자신이 사용하는 도구에서 무언가 출력되는 것을 보고 싶어하며, c) 스프링은 로깅에 의존성을 가지는 다양한 툴과 연동하기 때문이다. 애플리케이션 개발자의 목적 중 하나는 보통 외부 컴포넌트를 포함한 전체 애플리케이션에 대해 중앙의 통합된 로깅 설정을 가지는 것이다. 로깅 프레임워크가 다양해지면서 예전보다 선택하기가 더 어려워졌다.

스프링에 있는 필수 로깅 의존성은 Jakarta Commons Logging API(JCL)이다. JCL을 컴파일하고 JCL Log 객체를 스프링 프레임워크를 확장한 클래스에서 볼 수 있다. 스프링의 모든 버전에서 동일한 로깅 라이브러리를 사용하는 것이 사용자에게 중요하다. 스프링을 확장한 애플리케이션이더라도 뒷 단의 호환성이 보장되기 때문에 이전하기가 용이하다. 우리는 스프링의 모듈 중 하나를 명시적으로 commons-logging(JCL)에 의존하게 하고 다른 모듈들이 컴파일 시점에 해당 모듈에 의존하도록 하는 방법을 사용한다. 예를 들어, 메이븐을 사용하고 있으며, 어디서 commons-loggins에 대한 의존성을 가져와야 하는지 궁금하다면, 스프링에서 가져오도록 하고 명시적으로는 spring-core 모듈에서 가져온다.

commons-logging의 좋은 점은 애플리케이션이 동작하는데 필요한 것이 아무것도 없다는 것이다. 런타임 감지 알고리즘을 가지고 있어서 클래스패스에 잘 알려진 로깅 프레임워크가 있다면 적절한 것을 찾아 사용하도록 되어있다.(또는 여러분이 어떤것을 사용하고 싶은지 알려줄 수도 있다) 만약에 사용할 수 있는 것이 아무것도 없다면 JDK(java.util.logging 또는 줄여서 JUL)로부터 로그를 가져온다. 여러분의 스프링 애플리케이션이 대부분의 경우 잘 동작하며 잘 로깅 된다는 것을 알아야 하며, 그것은 중요하다.

불행히도, commons-logging의 안좋은 점은 역시 런타임 감지 알고리즘이다. 만약 시간을 되돌려 스프링을 새로운 프로젝트로 시작할 수 있다면 우리는 다른 로깅 의존성을 사용했을 것이다. 아마도 첫번째 선택은 많은 사람들이 애플리케이션에서 스프링과 함께 사용하고 있는 Simple Logging Facade for Java(SLF4J)일 것이다.

commons-loggins을 교체하는 것은 쉽다. 실행중에 클래스패스에 없도록 만들자. 메이븐에서 의존성을 제외할 수 있다. 스프링 의존성 선언 방법으로 인해 다음과 같이 한번만 선언하면 된다.

<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가 클래스패스에 없으니 깨질 것이다. 새로운 것을 제공하여 그것을 고쳐보자. 다음 절에서 우리는 어떻게 JCL 구현체의 대안으로 SLF4J를 사용하는지 예제를 살펴보겠다.

SLF4J 사용하기

SLF4J는 연동할 다른 프레임워크를 찾는 작업을 실행중에 하지 않고 컴파일 시점에 바인딩 하기 때문에 commons-loggins 보다 보다 깔끔한 의존성과 실행시 보다 더 효율적이다. 이것은 즉 실행중에 여러분이 어떤 것을 사용하고 싶은지 보다 명시적으로 선언하고 그것을 적절하게 설정해야 한다는 뜻이다. SLF4J는 여러 로깅 프레임워크에 대한 바인딩을 지원하기 때문에 여러분들이 기존에 사용하고 있던 것을 선택하고 해당 설정과 관리로 바인딩할 수 있다.

SLF4J는 JCL을 포함한 여러 로깅 프레임워크에 대한 바인딩을 제공한다. 또한 그 반대로 마찬가지다. 다른 로깅 프레임워크와 자신을 연결해준다. 따라서 SLF4J를 스프링에서 사용하기 위해서는 commons-logging 의존성을 SLF4J-JCL 브릿지 의존성으로 교체해야 한다. 그렇게 한번 하면 스프링 내부의 로깅 호출이 SLF4J에 대한 로깅 호출로 바뀐다. 따라서 만약 애플리케이션에서 다른 라이브러리들도 해당 API를 사용하고 있다면, 로깅을 설정하고 관리할 곳은 한 부분이다.

일반적인 선택은 스프링에서 SLF4J로 연결하고, SLF4J에서 Log4J로 명시적인 바인딩을 하는 것이다. 4개의 의존성을  명시적으로 제공해야 한다. brigde, SLF4J API, binding to Log4J, Log4J 구현체. 메이븐에서 다음과 같이 설정할 수 있다.

<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 보다 더 잘 동작할 것이다. 특히 OSGi 플랫폼같이 제약적인 컨테이너를 사용한다면 말이다. 이른바 실행시점이 아니라 컴파일 시점에 바인딩을 하기 때문에 성능상 장점을 얻을 수 있다.

SLF4J 사용자들 사이에서 보다더 일반적인 선택은 Logback에 지접 바인딩하여 과정을 짧게 하고 의존성을 더 줄이는 것이다. Logback이 SLF4J를 지겁 구현하기 때문에 추가적인 바인딩 과정을 제거해주기 때문에, 4개가 아니라 오직 두 개 라이브러리만 필요하다. (jcl-over-slf4j와 logback). 만약 그렇게 하면 slf4j-api 의존성 자체로 명시적인 의존성에서 제거할 필요가 있을지 모르겠다. 오직 한 버전 API 만 클래스패스에서 사용하길 원하기 때문이다.

Log4J 사용하기

많은 개발자들은 Log4J를 로깅 프레임워크로 사용하고 설정하고 관리한다. 효율적이며 잘 만들어졌다. 실제로 스프링을 만들고 테스트할 때 실행시에 사용하는 것이기도 하다. 스프링 또한 Log4j 설정과 초기화를 간편히 할 수 있는 것들을 제공한다. 따라서 몇몇 모듈은 Log4J에 대한 부가적인 컴파일 시점 의존성을 가지고 있다.

Log4j를 기본 JCL 의존성으로 사용할 때 필요한 것은 Log4J를 클래스패스에 두는것이 전부이다. 그리고 (log4j.properties 또는 log4j.xml을 클래스패스 루트에) 설정 파일을 제공하면 된다. 따라서 메이븐 사용자는 다음과 같이 의존성 선언을 하면된다.

<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다.

og4j.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 웹스피어 애플리케이션 서버(WAS)가 그중 하나이다. 이것은 보통 문제를 야기하고, 불행히도 정답은 없다. commons-logging을 애플리케이션에서 간단하게 제외하는 것이 대부분 상황에서 충분한건 아니다.

정리하자면: 문제는 JCL 또는 common-logging 자체가 아니라 commons-logging을 다른 프레임워크(보통 Log4J)에 바인딩하는 것과 관련이 있다. commons-logging이 런타임 탐색하는 방법이 몇몇 컨테이너가 사용하고 있는 예전 버전(1.0)과 현재 대부분의 사람들이 사용하고 있는 버전(1.1)과 다르기 때문이다. 스프링은 JCL API에서 별다른 것을 사용하지 않기 때문에 깨질것은 없지만, 조만간 로깅을 하려는 스프링 또는 여러분의 애플리케이션이 Log4J로 바인할 때 동작하지 않을 수 있다.

그런 경우 WAS를 사용할 때는 클래스로더 계층 구조(IBM은 이것을 "parent last"라 부른다.)를 변경하여 컨테이너가 아니라 애플리케이션이 JCL 읜존성을 제어하게 할 수 있다. 하지만 이 방법이 항상 가능한 건 아니지만,  여러분이 사용하는 컨테이너틔 버전과 기능에 따라 다양한 대안들이 공공연히 제시되고 있다.
top


Our plans for building OSGi application 요약

Spring DM/etc : 2009.03.20 20:51


참조 및 요약: Our plans for building OSGi application

OSGi 빌드 요구 사항

- 의존성 메타 데이터 중복 제거: 사용하는 빌드에 따라 pom.xml, ivy.xml에도 의존성을 정의하고 MANIFEST.MF 파일에도 의존성을 정의하는데 그러지 말고 한 곳에서 의존성을 정의하는 방법이 필요하다.

- 기존의 빌드 시스템 활용: 사용자들은 기존의 방식대로 메이븐 또는 Ant 빌드를 사용하고 싶어한다.

- 자동으로 MANIFEST.MF 파일 생성하기

- OSGi MANIFEST.MF 파일에서 의존성 가져오기: MANIFEST.MF 파일을 중심으로 의존성을 해결할 때 필요하다.

시나리오

1. 메이븐 + 이클립스 - pom.xml-주도: OSGi Manifest 파일은 메이븐 또는 이클립스 플러그인을 사용하여 자동생성한다. Manifest 생성에 필요한 대부분의 정보는 자바 코드에서 얻을 수 있지만 버전 정보는 그렇지 않다.  버전 정보는 pom.xml에서 그 정보를 가져올 수 있겠다. Manifest 템플릿을 통해서 그런 일을 할 수 있고 OSGi 속성이나 커스텀 헤더를 추가할 수 있겠다.

2. Ant + Ivy + 이클립스 - ivy.xml-주도: Ant 태스크로 manifest 파일을 생성한다. 위의 방법과 비슷하지만 단점으로 아직 이클립스에서 Ivy 2를 지원하는 플러그인이 없다. 개발자가 ivy.xml 파일을 작성하면 이클립스 플러긴을 사용해서 manifest를 만들고 이클립스 클래스패스를 자동으로 수정해주도록 한다.

3. 메이븐 + 이클립스 - MANIFEST.MF-주도: 개발자가 MANIFEST.MF 파일을 직접 또는 플러그인을 통해서 작성하면 그 파일을 기반으로 의존성을 처리한다. 이때 이클립스의 클래스패스 컨테이너를 이용한다. 테스트를 지원하기 위해 TEST.MF 파일에는 테스트에 필요한 의존성을 정의할 수 있게한다. 여기에 정의한 의존성은 테스트할 떄에만 가져온다. 남은 부분은 이것을 메이븐에 어떻게 적용하느냐 인데 현재 두 가지 옵션을 고려중이다. 하나는 pom.xml을 생성하는 것이고 다른 한 방법은 메이븐의 의존성 처리와 연동 또는 그것을 교체하는 것이다.

4. Ant + Ivy + 이클립스 - MANIFEST.MF-주도: 3번 방법과 비슷하고 2번의 단점인 Ivy 2 이클립스 플러긴 지원이 필요없어진다. Manifest-주도 이클립스 클래스패스 컨테이너를 사용할 것이기 때문이다.

OSGi 빌드 툴

- Bundlor: spring build 프로젝트에서 개발 중이며 몇 주후에 첫 번째 버전을 공개할 예정. 번들을 만들어 주며, manifest.mf 파일을 만들어 준다. http://www.springsource.com/repository/app/ 이곳에 있는 대부분의 번들을 이 툴로 만들었다. manifest 템플릿을 제공하여 커스터마이징 할 수 있게 해준다.

- BundlorEclipse: 이클립스 플러그인으로 Bundlor 기능을 이클립스에서 직접 사용할 수 있다. 소스 코드를 저장 버튼을 눌러 저장할 떄마다 manifest를 계속해서 수정해준다.

- 오프라인 의존성 리졸버

- Manifest 클래스패스 컨테이너

- 메이븐/Ivy 의존성 리졸버/pom.xml/ivy.xml  생성기

왜 bnd를 사용하지 않고 Bundlor를 만들었나?

처음에는 spring dm 프로젝트에서는 bnd를 사용했지만 다음의 부가 기능이 필요해서 만들었다.
- JDT-기반 코드 스캐닝
- 일부(Partial) 코드 처리하기
- 계속적인 manifest 생성

이클립스가 아닌 다른 IDE 활용하기

이클립스 말고 IntelliJ나 NetBeans 사용자를 위해 그쪽 팀에 Bundlor 핵심 라이브러리를 커밋했다. 그 결과 어떤 IDE 에서도 OSGi 개발 툴을 사용할 수 있게 됐다.

추가 요구사항

- 벌크 번들 생성

- 저장소-기반 코드 완성: dm 서버 저장소를 기반으로 소스 코드에서 자동 완성을 하면 자동으로 import 문을 추가해주고 Manifest에도 import 문을 추가해준다.
top


스프링 REST 지원 사용하여 애플리케이션에 Atom 뷰 추가하기



참조: http://blog.springsource.com/2009/03/16/adding-an-atom-view-to-an-application-using-springs-rest-support/

위 글을 실습해봤습니다. 재밌더군요~


top