Whiteship's Note

'스프링 3.0'에 해당되는 글 27건

  1. 2010.06.08 [회사일] GenericPersistentEnumFormatter 만들기
  2. 2010.05.20 Toby's 스프링 3.0 완독
  3. 2010.05.19 Toby's 스프링 3.0 @MVC를 읽고서 (3)
  4. 2010.05.14 Toby's 스프링 3.0 데이터 액세스 기술을 읽고서
  5. 2010.05.13 Toby's 스프링 3.0 10장 IoC 컨테이너와 DI를 읽고서 (8)
  6. 2010.05.11 Toby's 스프링 8, 9장을 읽고서
  7. 2010.05.10 Toby's 스프링 핵심기술 응용을 읽고서.. (2)
  8. 2010.03.16 [스프링 3.0] @Value 이용해서 기본값 설정하기
  9. 2010.02.18 [스프링 3.0] PropertyEditorRegistry가 이길까 ConversionService가 이길까 (2)
  10. 2010.01.28 [스프링 3.0] 로깅은 SLF4J를 이용한 Log4J로 (1)
  11. 2009.12.17 스프링 프레임워크 3.0이 GA 됐다. (4)
  12. 2009.12.11 [스프링 3.0] 스프링 bean과 일반 자바 객체가 호출하는 @Bean 메서드의 차이
  13. 2009.11.16 [스프링 3.0] RC2 릴리즈~
  14. 2009.10.18 [스프링 3.0] @Valid 실습
  15. 2009.09.28 [스프링 3.0] 애노테이션 기반 스케줄링 (2)
  16. 2009.08.20 [스프링 3.0 OXM] 14. Marshalling XML using O/X Mappers 4
  17. 2009.08.19 [스프링 3.0 OXM] 14. Marshalling XML using O/X Mappers 3
  18. 2009.08.13 [스프링 3.0 OXM] 14. Marshalling XML using O/X Mappers 2
  19. 2009.08.13 [스프링 3.0 OXM] 14. Marshalling XML using O/X Mappers 1
  20. 2009.06.10 [Spring 3.0] HiddenHttpMethodFilter (4)
  21. 2009.04.21 Spring Expression Language(SpEL) (2)
  22. 2009.04.20 What's new in Spring 3.0? (2)
  23. 2009.03.18 스프링 REST 지원 사용하여 애플리케이션에 Atom 뷰 추가하기
  24. 2009.03.09 REST in Spring 3: @MVC (8)
  25. 2009.02.26 Petclinic을 통해 스프링 3.0 주요기능 살펴보기 (6)
  26. 2008.11.29 스프링 프레임워크 3.0 m1 임박.
  27. 2008.10.10 Spring 2.5 on the Way to 3.0 - 유겐 휄러

[회사일] GenericPersistentEnumFormatter 만들기

프로젝트/SLT : 2010.06.08 16:40


GenericPropertyEditor도 만들었었는데 Formatter라고 못만들까 하는 생각에 만들어봤습니다. Locale은 무시해서;; 반쪽짜리긴 하지만 그래도 쓸만합니다.

포매터를 만들 대상은 PersuistentEnum 입니다. 자세한 내용은 이전 글에서 확인하시기 바랍니다.

http://whiteship.me/search/PersistentEnum

간단히.. Enum을 사용할 떄 필요한 기능을 정의한 PersistentEnum 인터페이스를 사용할 때 필요한 UserType이나 Formatter를 쉽게 만들 수 있게 GenericPersistentEnumUserType GenericPersistentEnumProperyEditor등을 만들었습니다.

public class PersistentEnumFormatter<E extends PersistentEnum> implements Formatter<E> {

    protected Class<E> enumClass;

@SuppressWarnings("unchecked")
public PersistentEnumFormatter() {
ParameterizedType genericSuperclass = (ParameterizedType) getClass()
.getGenericSuperclass();
Type type = genericSuperclass.getActualTypeArguments()[0];
if (type instanceof ParameterizedType) {
this.enumClass = (Class) ((ParameterizedType) type).getRawType();
} else {
this.enumClass = (Class) type;
}
}
    
    public String print(E object, Locale locale) {
        return object.getDescr();
    }

    public E parse(String text, Locale locale) throws ParseException {
        return PersistentEnumUtil.valueOf(enumClass, Integer.parseInt(text));
    }
}

제네릭 타입이 필요해서 생성자에서 타입 추론을 사용했는데 그 코드만 빼면 너무도 간단합니다. PE 만들때랑 비슷하거나 더 쉬운것 같습니다.

그래도 왠지 불안하니깐 테스트 해봤습니다.

public class PersistentEnumFormatterTest {

    CodeCateFormatter ccf;

    @Before
    public void setUp(){
        ccf = new CodeCateFormatter();
    }

    @Test
    public void testPrint() throws Exception {
        assertThat(ccf.print(CodeCate.SIZE, null), is("사이즈"));
    }

    @Test
    public void testParse() throws Exception {
        assertThat(ccf.parse("10", null), is(CodeCate.COLOR));
    }

    @Test
    public void testParseNotInValue() throws Exception {
        assertThat(ccf.parse("0", null), is(nullValue()));
    }

    @Test(expected = NumberFormatException.class)
    public void testParseWrongValue() throws Exception {
        assertThat(ccf.parse("캐스팅에러", null), is(nullValue()));
    }

    class CodeCateFormatter extends PersistentEnumFormatter<CodeCate> {

    }

}

흠냐 이제 포매터로 갈아탈 시간이 됐군요. 
어서 CodeCate 이늄(enum)좀 추가하고 마무리 해야겠어요.
저작자 표시
신고
top


Toby's 스프링 3.0 완독



아직 나오지도 않은 책을 벌써 완독했다. 캬.. 이런 특권이 있나...

열심히 봤는데 10일정도 걸린것 같다. 읽는 족족 소화되는 내용들이 아니라서 좀 힘들다. 마지막에 읽은 내용들은 AOP과 LTW, 콘텍스트 테스트 프레임워크, 스프링 기타 기슬과 스프링 학습법 이었다. 마지막 부분인데 지면 관계상인지 이 책의 앞부분에 비하면 다소 함축적이었다.

나도 그동안 감상을 수도 없이 적었으니 이번엔 생략이다.ㅋ

이 책의 앞에서는 열심히 테스트로 내용 검증도 해주고 그랬었는데 2부에 들어서면서부터 방식이 바뀌었다. 그렇다고 해당 내용 검증을 하지 않을 분이 아니다. 저자인 Toby님은 완벽주의자다. 이 책과 같이 제공될 소스 코드에 보면 책에서 언급한 내용을 일일히 테스트 코드로 작성한 것을 볼 수 있다. 

다음 봄싹 스터디에서는 해당 테스트 코드를 가지고 스터디를 해볼까 생각중이다. 또 해당 테스트 코드를 오픈 소스로 계속 다듬어 볼 생각도 있다. 학습 테스트를 오픈소스로 만들어 두면 차후에 스프링을 처음 쓰거나 해당 기능을 처음 쓰는 사람들에게 도움이 될 것 같다.

저작자 표시
신고
top


Toby's 스프링 3.0 @MVC를 읽고서



하악하악... 무려 워드로 130p 가까운 걸 읽었더니 머리가 혼란스럽다. 내가 잘모르던 것이 가장 많이 등장한 챕터인것 같다. 챕터 제목이 @MVC 라고 스프링 레퍼런스에 있는 @MVC 부분과 대응해서 생각했다간...
ㅎㅎㅎㅎ.......

이번 장의 겉모습은 @MVC 이지만 난 왠지 스프링 MVC 확장 프레임워크에 대한 힌트를 얻은 것 같다. 솔직히 말해서 대충 쓰려면 몰라도 되는 것들이 제법 있지만 그건 정말 대충 쓸 때의 이야기이고 스프링 강의를 한다던지, 스프링 @MVC 기반 프레임워크를 만들거라든지, 제대로 알고 쓰고 싶다는 경우에는 반드시 알아야 하는 내용들이 가득 들어있다. 지면 관계상 다소 함축적으로 설명한 부분도 없자나 있다. 그런 부분은 API나 레퍼런스를 보면 쉽게 알 수 있을 것이고 저자가 권하듯이 소스 코드를 보면 더 확실하게 알 수 있을 것 같다.

이번 장은 맨 처음부터 끝까지 긴장하면서 봐야했다. 그래서 좀 힘들었다. 아 마지막에 form 태그 설명할떈 조금 쉬엄쉬엄 봤는데 그전까진 정말 뇌가 100m 달리기를 하는듯한 기분이다. 그중에서 틀린 설명이나 잘못된걸 집어내라고 하니 머리가 빠질것 같은 기분이다. 번데기에서 주름 없는 곳을 찾으란 얘기랑 같은 거다.

이 장에서 제일 재밌게 본 부분은 상속 관계에서 @RequestMapping 동작 방식이다. 그밖에도 스프링 3에 추가된 컨버터와 포매터 그리고 모델의 일생, 메시지 컨버터, @MVC 확장 포인트 등을 설명해준다. @MVC를 사용해온지 꽤 됐는데도 모르는 기능이 많았다. 마지막 부분에는 핸들러 메서드의 인자로 받을 수 있는 것을 확장하는 방법도 나오는데 정말 대박이었다.. 뭐 이런 기능들까지 있나 싶을정도로.. 까오..

이제 나머지를 달려야겠다.
저작자 표시
신고
top


Toby's 스프링 3.0 데이터 액세스 기술을 읽고서



JDBC, iBatis, JPA, Hibernate를 사용하여 DAO를 사용하는 방법과 로컬 트랜잭션, JTA 트랜잭션 사용법까지 나와있다. 특히 이중에서 내가 자주 안써본 JDBC, iBatis, JPA 내용과 JTA 트랜잭션이 꽤 재미있었다.

JDBC 코딩 하시는 분들께는 거의 필수인 JdbcTemplate이나 SImpleJdbcTemplate은 대부분 익숙할 것이다. 하지만 그게 끝이 아니었다. 이것들을 기반으로 객체 지향 API로 쿼리 객체를 만들고 재사용할 수 있는 API도 제공한다. 스프링 빨간책에서 커맨드 패턴과 JdbcTemplate을 이용해서 한단계 더 추상화 시킨 SqlUpdate와 SqlQuery를 볼 수 있었는데 그보다 더 개선된 새로운 API인것 같다. (SimpleJdbcInsert API를 보니 2.5에 추가된 것인가 보다.)

iBatis보다는 JPA 내용이 더 재미있었다. 최근 JPA 2.0이 발표되면서 Hibernate를 JPA 프로파이더로 사용하고 JPA를 사용해볼까 고민하던 중이었기 때문인지도 모르겠다. 하지만 그 뿐이 아니다 JPA를 사용하는 방법에는 어떤 것들이 있고 각각의 장단점 비교가 나온다. 특히 이부분에서 CDI와 관련된 스코프 관련 내용도 나오는데 예전에 토비님 블로그에서 이상한 공격(?)을 받았던 글이 떠올랐다. 그 둘을 연관지어서 읽어보면 더 재미있을 것 같다.

Hibernate는 JPA에 비해 적용방법은 간단해 보였다. 이유는 JPA 처럼 좀 더 쉽게 쓰게 해주려는 마술을 적용하지 않았기 때문일 것이다. 그래서 매번 .getCurrentSession()을 해줘야하지만 머.. 결국은 선택이다.

또 KSUG 포럼에 종종 올라오는 질문 중에 하나인 트랜잭션 관련 내용이 알차다. 데이터소스 하나 트랜잭션 매니저 하나인 아주 간단한 경우부터 JTA까지 다룬다. 톰캣에서 JTA를 사용하는 예제까지 보여주고 있으며 하나의 데이터베이스에 대한 JDBC, 하이버 DAO가 있을떄 어떻게 그리고 어떤 트랜잭션 매니저를 왜 사용하면 되는지 설명해준다. 그밖에 여러 경우를 전부다..

오늘도 별로 꼬투리 잡을께 없다. +_+
저작자 표시
신고
top


Toby's 스프링 3.0 10장 IoC 컨테이너와 DI를 읽고서



결론은 다시보고 있다. 다시 보고 싶은 부분이 생겼다. 들어있는 내용이 꽤 많기 때문에 그 중에서 더 자세히 살펴보고 싶은 부분이 분명히 생길것이다. 그래서 결국 나처럼 다시 보게 될 것이다.

이 책을 쓰느라 얼마나 많은 노력과 학습을 하셨는지 이 장에 잘 묻어나온다. 특히 모든 빈 등록 방법 설명, 장단점 비교, 전략 분석. 모든 빈 의존관계 설정 방법 설명, 장단점 비교, 전략 분석은 토비님의 완벽주의 성향을 잘 드러낸다.

스프링 웹 애플리케이션은 거의 대부분 애플리케이션 콘텍스트 상속 구조로 되어있다. 이것을 잘 이해하지 못하면 AOP가 적용되지 않는다느니 트랜잭션이 되지 않느다느니 원인을 찾기도 힘든 문제들을 만들어 낼 수도 있고 그 문제를 해결하지도 못한다. 그것에 대한 아주 명확한 이해와 해결책을 제시하는 내용이 들어있다. 이걸 모르고 스프링 개발을 하고 있다면 무늬만 스프링 개발자라고 하고 싶을 정도로 중요한 내용이기 때문에 반드시 숙지하도록 하자.

프로토타입과 관련된 내용도 주옥같다. 아주 오래전 KSUG 포럼에 프로토타입 스코프 빈을 참조하는 싱글톤 스코프 빈이 있을때 프로토타입 스코프가 제대로 동작하도록하는 여러가지 방법을 논의한적이 있었다. 사실은 Toby님의 일방적인 퀴즈에 불과했지만 그때 메신저를 통해 들었던 정답과 그 이후에 추가된 해결책까지도 설명하고 있다. 레퍼런스나 API 문서를 빠듯하게 뒤져도 안나올만한 방법이 소개되고 있다. 싱글톤 빈만 사용하면 되지 머.. 라고 안일한 생각을 가진 스프링 사용자가 아니라면 꼭 살펴보고 학습해야 한다.

이밖에도 레퍼런스나 API 문서에서 조차 찾기 힘든 내용이 한둘이 아니다. 그런 내용을 이렇게 친절하게 설명해주는.. 그것도 한글로 된 책을 볼 수 있다는 것은 가히 축복이다.

아. 마지막으로 꼬투리 하나만 잡자면 왠지 10장부터는 약간 토비님 블로그를 읽는 느낌이 난다. 그런데 어쩔 수 없다 저 많은 내용을 더 쉬운 말투와 구체적인 설명과 그림으로 다 풀어내려면 200~300p짜리 책한권이 될 것 같다. 내용자체가 쉽지 않기 때문일 수도 있다. 그렇다고 무슨 안드로메다 수학공식도 아니니까 겁먹진 말자.
저작자 표시
신고
top


Toby's 스프링 8, 9장을 읽고서



8장은 스프링에 관한 이야기이다. 스프링이란 무엇인가? 스프링의 목적? 그 목적을 달성하는 방법을 설명하며 스프링 삼각형이라 불리는 IoC/DI, AOP, PSA를 자세히 설명해준다. 또한 POJO 프로그래밍에 대해 설명한다. 

그 중에서 기억에 남는 부분은 "복잡함을 해결한다."라는 부분인데 이 이야기는 2008년 Spring One Ameria 컨퍼런스에 참석하여 직접 들은 이야기라 감회가 새로웠다. 여기서는 그 복잡함이란 무엇인지 또 스프링은 그것을 어떻게 제압하겠다는 것인지 잘 설명해주고 있다.

POJO 프로그래밍에 대한 내용역시 유익하다. POJO라는 단어가 난무하는 요즘 POJO에 대해 제대로 집고 넘어갈 필요가 있는데 그런 간지러움을 잘 긁어주고 있다. 특히 평소 JPA를 사용한 도메인 클래스가 POJO인건지 아닌건지 고민이었는데 그런 고민을 해결하는데 실마리를 제공해주는 기준을 제시하고 있다.

이외에 스프링 삼각형에 대해서는 이미 1부에서 찐하게 살펴본 내용을 이론적으로 점검하는 기분이 들었다. 원래는 8장이 제일 처음이었다고 했는데 1부 맨 뒤로 돌리신건 100번 잘하신것 같다. 아무래도 8장부터 읽기 시작했다면 지레겁먹고 책을 덮었을 수도 있겠다.

9장은 본격적인 2부 시작으로 뭔가 코딩을 할 것 같은 기세이다. 프로젝트를 세팅하고 아키텍처를 논한다. 프로젝트는 세팅이야 스프링 책인지라 STS와 Eclipse+Spring IDE 이야기가 주를 이룬다. 가장 흥미롭우며 9장의 주를 이루는 부분은 사실 그 뒤에 있는 아키텍처 이야기다. 이 부분 토비님 세미나에서 다룰 주제이기도 하고 개인적으로 가장 궁금한 부분이기도 했다. 이 부분을 읽으면서 예전에 시도하다 말았던 아키텍처를 다시 한번 시도해보고 싶다는 생각이 들었다.

자.. 이제 드뎌 10장을 달릴 차례다.
저작자 표시
신고
top


Toby's 스프링 핵심기술 응용을 읽고서..



먼저 이 장의 제목은 별로다. 이 장에 들어있는 내용을 다 나타내고 있지 못하다. 흠.. 읽고나서 다시 제목을 생각해보니 이번 장은 "스프링 스타일 코딩"이 더 좋을지도 모르겠다.

이번 장에서 살펴볼 수 있었던 스프링의 기능은 내가 미처 몰랐던 기능인 내장 DB 지원 기능을 비롯해서 3.0에 새로 추가된 OXM 그리고 필수로 알아야 하는 리소스 지원 등을 다루고 있다. 이 기능들을 유기적으로 연결하여 SqlService라는 것을 개발하는데 그 과정이 정말이지 놀랍다.

왜 놀라운지는 읽어보는 사람들만이 알수 있겠지만, 이 장을 읽으면서 내내 느낀점은 이 책은 스프링 사용자 뿐 아니라 모든 개발자가 읽어야 한다는 것이다. 이번장에서 SOLID라 일컫는 객체 지향 기본 원칙들을 아무런 거부감 없이 자연스럽게 살펴볼 수 있으며 사용하기 좋은 API 설계 방법이나 점진적인 변화, 진화를 통한 개발 방법을 살펴볼 수 있다. 이런것들은 상당히 딱딱하고 탁상공론 적이며 형이상학적인 주제가 될 수 있는데 반해 이 책에서는 그것들을 항상 눈에 보이는 코드와 테스트를 가지고 증명해 보인다. 또한 이 책의 스타일인 '차분차분'과 '단계적'인 방법을 통해서 살펴보기 때문에 체할 걱정은 없으며 굉장히 실용적이다.

지난주 봄싹 디자인패턴 스터디에서 SOLID 원칙을 학습했지만 탁상공론에 그칠만한 내용밖에 못다뤄 굉장히 아쉬웠다. 물론 이론적인 내용도 필요하다지만 사실 그런 이론은 시험 볼때나 필요한 것이지 코딩에는 별 도움이 안 된다. 코딩에 도움이 되지 않는 이론이 무슨 소용이란 말인가. 순수 이론으로써의 가치를 가지고자 정리된 원칙들이 아닐 것이다. 그러한 원칙들을 고려하여 코딩하는 것이 어떤 것인지... 그로인해 어떤 스타일의 코드가 탄생되는지 보고 싶다면 이 책을 꼭 보시라권하고 싶다.

나 역시 백날 스프링을 쓰면 머하나.. 스프링에 어울릴만한 코드는 한 줄도 작성하지 못하는데.. 라며 자괴감에 빠졌던 적이 있다. 머 그렇다고 지금도 크게 달라진건 없지만 이 챕터가 그러한 자괴감에서 나를 꺼내주는데 한몫 할것 같다. 역시 이 책은 스프링을 발판삼아 더 나은 개발자가 되고 싶은 분들을 위한 책이다. 자 이제 2부를 달려보자.
저작자 표시
신고
top


[스프링 3.0] @Value 이용해서 기본값 설정하기

Spring/3.0 : 2010.03.16 18:04


@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration
public class ValueTest {

    @Autowired Whiteship whiteship;

    @Test
    public void defaultName(){
        assertThat(whiteship.getName(), is("keesun"));
    }

}

@Component
public class Whiteship {

    @Value("keesun")
    private String name;

    public String getName() {
        return name;
    }
    
    public void setName(String name) {
        this.name = name;
    }
}

악.. 저녁 약속이 있어서 길게 정리는 못하겠네요. 


이것도 DI용 애노테이션이라는거..


저작자 표시
신고
top


[스프링 3.0] PropertyEditorRegistry가 이길까 ConversionService가 이길까

Spring/3.0 : 2010.02.18 17:24


public class Whiteship {

    String name;

    public Whiteship(String name) {
        this.name = name;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}


public class SpringSprout {

    private Whiteship whiteship;

    private int num;

    public Whiteship getWhiteship() {
        return whiteship;
    }

    public void setWhiteship(Whiteship whiteship) {
        this.whiteship = whiteship;
    }

    public int getNum() {
        return num;
    }

    public void setNum(int num) {
        this.num = num;
    }
}

이렇게 두 개의 클래스가 있을 때 Whiteship을 SpringSprout로 주입하는 빈 설정을 다음과 같이 했다.

    <bean class="sandbox.convert.SpringSprout">
        <property name="whiteship" value="keesun"/>
        <property name="num" value="1"/>
    </bean>

동작할까 안할까?

당연히 안한다. Whiteship 타입이 필요한데 keesun이라는 문자열을 던져주다니 장난 하는게냐 라고 예외를 던질꺼다.

하지만 되게 만들 수 있다. 이전까지는 PropertyEditorSupport 클래스를 확장하여 아주 손쉽게 구현할 수 있었다.

public class WhiteshipPE extends PropertyEditorSupport {

    @Override
    public String getAsText() {
        return ((Whiteship)getValue()).getName();
    }

    @Override
    public void setAsText(String name) throws IllegalArgumentException {
        setValue(new Whiteship(name));
    }
}

이런 코드는 특히 MVC에서 바인딩 할때 매우 유용하다. 이걸 안쓰면 request에서 일일히 꺼내서 노가다를 해야하는데 난 절대로 그러고 싶지 않다.

그런데 PE의 문제는 쓰레드-세이프하지 않다는 것이다. 그래서 PE를 등록할 때 조심해야 한다. 특히 전역 변수를 가지는 PE를 싱글톤으로 바인더에 등록해버리지 않았나 조심해야 한다. 반드시 그때 그때 new를 사용해서 등록해 주도록 하고 PE 생성자에 필요한 레퍼런스를 전달해주는게 안전하다. 아마 이 내용도 사부님 책에 들어갈 것 같으니 자세한 내용은 그 책을 참고하도록 하자.

PE의 대안이자 좀 더 범용적인 변환기 역할로 3.0에 도입된 것이 ConversionService이고 ConversionServiceFactoryBean에 Converter, ConveterFacrtory, Formatter 등을 등록해놓고 변환을 부탁할 수 있게 되었다.

public class WhiteshipConverter implements Converter<String, Whiteship> {
    public Whiteship convert(String source) {
        return new Whiteship(source);
    }
}

그런데;; PE와 역할이 중복되는데;;; 둘 다 빈으로 등록해둘수 있다.


    <bean class="org.springframework.beans.factory.config.CustomEditorConfigurer">
        <property name="propertyEditorRegistrars">
            <bean class="sandbox.convert.CustomPERegister">
            </bean>
        </property>
    </bean>

    <bean id="conversionService" class="org.springframework.context.support.ConversionServiceFactoryBean">
        <property name="converters">
            <set>
                <bean class="sandbox.convert.WhiteshipConverter"/>
            </set>
        </property>
    </bean>

결국 문제는 대체 String을 Whiteship으로 바꿔야 할 때 PE를 쓸 것이냐 CS를 쓸 것이냐이다. 무엇을 쓰게 될지... 그게 궁금했었다. 그런데 마침 오늘 사부님이 퀴즈를 냈고;; 난 스케줄을 팽개치고 매달렸다;;

1차 문제 상황

CS와 PE가 등록되어 있을 때 PE가 이겼다.
하지만 난 CS가 이기는 경우를 예제에서 본적이 있었다. 그래서 도무지 납득이 되지 않았고 어떻게 설정해야 가능한지 궁금했다.

CS만 등록했을 땐 CS로 동작했다.
PE만 등록했을 땐 PE로 동작했다.
둘다 등록했을 땐 PE가 동작헀다.

2차 문제 상황

Whiteship만 가지고 테스트를 했었는데 기본 타입도 추가해봤다. int num이 그것이다. 이제 더 큰 문제가 생겼다.
Whiteship만 PE가 이기고 나머지 기본 타입은 CS가 이겼다.
정말 깜놀이었다. 이사실을 발견하지 않았다면 난 그냥 클래스로더를 공부했을 것이다.

어디선가 기본 PE를 덮어쓰거나 없애버린 거 아닌지 궁금했고 소스 코드를 뒤져보기 시작했다.
시간이 손살같이 지난간다.
우울해지기 시작한다.

3차 결론

소스 코드를 뒤적거리다가 ConvertingPropertyEditorAdapter 클래스를 찾았다.
이 클래스는 ConversionService를 사용해서 PE를 노출시켜주는 어댑터다.
겉으로는 PE를 등록한것 같지만 실제로는 ConvesionService를 사용하는 것이다.ㅋ

스프링에서 내부에서 저걸 사용해서 기본 PE들을 등록하도록 바꿨는지는 확인하지 않았다.
왠지 답이 아닌것 같다. OTL..
내가 졌다.

트릭같은 기법을 써서라도 PE를 누르고 아니 속이고 CS가 동작하게 했으니...그만 놓아줄 수 있을 것 같다.
어서 사부님 책이 나와주길....

ps: 위에 나온 코드는 급조한 코드오니 조심할 부분을 건너뛴 곳도 있습니다. 주의하세요.
신고
top


[스프링 3.0] 로깅은 SLF4J를 이용한 Log4J로

Spring/3.0 : 2010.01.28 17:08


스프링을 사용하면 기본적으로 JCL(자카르타 커먼스 로깅)을 사용하게 되는데 JCL이 실제 로거를 선택하는 시점이 런타임이라 클래스로더 문제라던가 런타임시 오버헤드가 생길 수 있는데 이것을 개선한 구현체 SLF4J로 갈아타면 그러너 문제 걱정을 덜 수 있겠습니다. 보너스로 문자열 연결로 발생하는 오버 헤드도 개선할 수 있으며 귀찮은 if문 추가하는 코딩에서 벗어날 수 있는 문법? API?를 제공해줍니다. 그래서인지 스프링도 3.0부터는 본격적으로 spring-core가 의존하는 JCL을 SLF4J로 교체하고 사용하는 예제 및 레퍼런스 설명을 보여주고 있습니다..

갈아타는 방법은 다음과 같습니다.

1. 스프링에서 참조하는 JCL 라이브러리를 빼버리기.
2. JCL-over-SLF4J 추가하기.
3. SLF4J API 추가.
4. SLF4J-log4j 추가.
5. log4j 추가.

이전에 스프링소스 블로그와 레퍼런스에 올라온 방법은 이걸 그대로 메이븐 의존성으로 옮겨적고 있지요.

        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>${org.springframework.version}</version>
            <exclusions>
                <!-- Exclude Commons Logging in favor of SLF4j -->
                <exclusion>
                    <groupId>commons-logging</groupId>
                    <artifactId>commons-logging</artifactId>
                 </exclusion>
            </exclusions>
        </dependency>

        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-api</artifactId>
            <version>${org.slf4j.version}</version>
        </dependency>
        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>jcl-over-slf4j</artifactId>
            <version>${org.slf4j.version}</version>
            <scope>runtime</scope>
        </dependency>
        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-log4j12</artifactId>
            <version>${org.slf4j.version}</version>
            <scope>runtime</scope>
        </dependency>
        <dependency>
            <groupId>log4j</groupId>
            <artifactId>log4j</artifactId>
            <version>1.2.15</version>
            <exclusions>
                <exclusion>
                    <groupId>javax.mail</groupId>
                    <artifactId>mail</artifactId>
                </exclusion>
                <exclusion>
                    <groupId>javax.jms</groupId>
                    <artifactId>jms</artifactId>
                </exclusion>
                <exclusion>
                    <groupId>com.sun.jdmk</groupId>
                    <artifactId>jmxtools</artifactId>
                </exclusion>
                <exclusion>
                    <groupId>com.sun.jmx</groupId>
                    <artifactId>jmxri</artifactId>
                </exclusion>
            </exclusions>
            <scope>runtime</scope>
        </dependency>

1번은 단순히 JCL 라이브러리에 의존할 생각이 없기 때문에 빼버리는 것이고, 그때 JCL에 의존하는 클래스들이 깨질 텐데 그것을 JCL-over-SLF4J를 이용해서 겉은 JCL 같지만 내부에서는 SLF4J API를 호출하도록 일종의 어댑터 나 다리 역할을 해주는 라이브러리를 추가하고, 인터페이스 격인 3. SLF4J API를 추가한 뒤 실제 사용할 로거로 SL4J를 구현한 4. SLF4J-Log4J 라이브러리를 추가합니다. 마지막으로 최종적으로 사용할 로거 5. Log4J를 추가한 것입니다. 이때 Log4J가 불필요하게 참조하는 jmx, mail, jms 등의 라이브러리를 제외시켜줍니다.

만약에 Log4J가 아니라 다른 로거를 사용할 거라면 4번과 5번을 교체하면 될테고 JCL 뿐 아니라 log4j에 대한 직접 호출도 slf4j로 오게 하려면 2번 대신 log4j-over-slf4j을 추가하면 되겠습니다.

굉장히 장황니다. @_@;; 하지만 뭐.. 좋다는데.. 갈아타긴 해야겠죠.

출처: SLF4J in 10 slides, by Ceki Gülcü

위와 같은 설정은 스프링 3.0 예제와 레퍼런스에서 사용하고 있습니다. 정말 장황합니다. 일단 여기서 1, 2번은 필수다 하지만 레퍼런스와 블로그 글에도 나와있듯이 그 이하 3, 4, 5는 Logback이라는 SLF4J API 구현체로 한방 설정이 가능합니다.

logback은 크게 세 가지 모듈로 나뉘는데 그 중에 SLF4J API 구현체인 classic 모듈이 있고, Log4J를 개선한 core 모듈이 있습니다. logback 모듈을 가져오면 위에서처럼 log4j가 끌고오는 부가적인 라이브러리도 없고 깔끔하게 log4j API를 사용할 수 있습니다.

        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>${org.springframework.version}</version>
            <exclusions>
                <!-- Exclude Commons Logging in favor of SLF4j -->
                <exclusion>
                    <groupId>commons-logging</groupId>
                    <artifactId>commons-logging</artifactId>
                 </exclusion>
            </exclusions>
        </dependency>

        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>jcl-over-slf4j</artifactId>
            <version>${org.slf4j.version}</version>
            <scope>runtime</scope>
        </dependency>
        <dependency>
            <groupId>ch.qos.logback</groupId>
            <artifactId>com.springsource.ch.qos.logback.classic</artifactId>
            <version>0.9.9</version>
        </dependency>

따라서 굳이 Log4J가 아닌 다른 로거로 갈아탈 계획이 없다면 이렇게만 설정해도 되겠습니다. 로깅 설정만 거의 1/3로 줄어듭니다.

사용법은

1. SLF4J API를 이용해서 로거를 만들고..

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

Logger log = LoggerFactory.getLogger(AccountJsonBindingTests.class);

2. 다음과 같이 로깅하면 됩니다.

log.info("name is {}", name);

+를 사용해서 문자열 연산을 할 필요도 없고, if문을 줘서 문자열 연산을 막을 필요도 없습니다.

3. log4j 설정은 프로퍼티 파일이나 XML로 할 수 있는데 스프링 3.0 예제는 보통 XML을 사용하더군요. src와 test 소스 폴더 하위의 클래스패스 루트에 각각 다음과 같은 log4j.xml 파일을 둡니다.

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE log4j:configuration PUBLIC "-//LOGGER" "log4j.dtd">

<log4j:configuration xmlns:log4j="http://jakarta.apache.org/log4j/">

    <!-- Appenders -->
    <appender name="console" class="org.apache.log4j.ConsoleAppender">
        <param name="Target" value="System.out" />
        <layout class="org.apache.log4j.PatternLayout">
            <param name="ConversionPattern" value="%-5p: %c - %m%n" />
        </layout>
    </appender>

    <!-- 3rdparty Loggers -->
    <logger name="org.springframework.core">
        <level value="info" />
    </logger>

    <logger name="org.springframework.beans">
        <level value="info" />
    </logger>
   
    <logger name="org.springframework.context">
        <level value="info" />
    </logger>

    <logger name="org.springframework.web">
        <level value="info" />
    </logger>

    <!-- Root Logger -->
    <root>
        <priority value="warn" />
        <appender-ref ref="console" />
    </root>
   
</log4j:configuration>

src와 test 간의 차이는 마지막 부분의 <root> 안의 <priority>가 src에서는 warn이고 test에서는 info라는 것 뿐이 없습니다. 이 설정에서는 Log4J를 사용하고 있는데.. logback API를 이용해서 설정해도 당근 잘 동작합니다.

신고
top


스프링 프레임워크 3.0이 GA 됐다.

Spring/3.0 : 2009.12.17 11:12


원문: http://www.springsource.org/node/2266
봄싹 위키: http://springsprout.org/wiki/1495.do

긴 여정을 거쳐, 드디어 스프링 3.0 GA (배포)를 이용할 수 있게 됐다는 것을 발표하게 되어 기쁘다! 스프링소스는 지금 축제 중이다. 여러분도 같이 파티에 참여하기 바란다. :)

가장 최근 소식으로, 스프링 3.0 GA는 이제 (지난주에 배표된 GlassFish v3과 같은) 자바 EE 6 파이널 런타임 환경과 호환가능하며 이미 (EcliseLink 2.0 같은) JPA 2.0 파이널을 지원하고 있다. 또한 (JSR-250 v1.1에) 새로 추가된 @ManagedBean 컴포넌트 스캐닝을 지원하며 애노테이션-주도 의존성 주입에 활용할 (JSR-330) @Inject와도 잘 동작한다.

여러분의 편의를 위해 스프링 3.0 전체 주요 기능을 요약했다.

* 스프링 EL(SpEL): 빈 정의에서 사용할 코어 표현식 파서로, 내부 빈 구조와 환경적인 데이터 구조 속성 값에  #{...} 문법을 사용하여 접근할 수 있다.

* 애노테이션-기반 컴포넌트 지원 확장: (스프링 JavaConfig로 알려져 있는)설정 클래스 개념과 애노테이션 팩토리 메서드를 도입했다. 스프링은 또한 환경 값을 @Value 표현식으로도 주입할 수 있게 해주며, 동적인 #{...} 표현식과 정적인 ${...} 대체공간(placeholder)을 이용하여 설정 구성(configruation settings)을 참조할 수 있게 해준다.

* 강력한 스테레오타입 모델: 메타 애노테이션을 사용한 '숏컷' 애노테이션 생성을 지원한다. 예를 들어 기본 스코프와 기본 트랜잭션 특성을 가지고 있는 커스텀 스테레오타입을 만들 수 있다. @Service, @Scope("request"), @Transactional(readOnly=true)를 모두 가지고 있는 @MyService 애노테이션 한개를 만들어 사용할 수 있다.

* 표준화된 의존성 주입 애노테이션: 스프링 3.0은 자바 애노테이션-기반 의존성 주입에 관한 JSR-330 스펙을 완전히 지원한다. @Inject와 관련된 qualifier와 providier 모델을 스프링 내부의 @Autowired에 대한 대체제로 지원한다.

* 제약 애노테이션 기반의 선언적인 모델 검증: JSR-303 빈 검증기(validation provider)에 대한 스프링-스타일 구성을 했다. 애노테이션을 이용한 검증 옵션을 스프링 MVC에서 이용할 수 있다. 스프링의 바인딩 결과 기능을 통해 제약사항 위반에 대한 일관적인 뷰를 제공한다.

* 강화된 바인딩과 애노테이션-기반 포매팅: 표준 PropertyEditor에 대한 대체제로 Converter와 Formatter SPI를 제공한다. 포맷팅은 JSR-303 제약과 비스한 스타일로 애노테이션을 이용할 수 있다. 예를 들어 @DateTimeFormat을 사용할 수 있다. 또한 새로운 mvc 네임스페이스를 사용하여 스프링 MVC에 포맷팅과 검증기를 편하게 설정할 수 있으니 확인해 보기 바란다.

* 방대한 REST 지원: REST스타일 요청 매핑, @PathVariable 매개변수를 사용한 URI 변수 추출, 컨텐츠 교섭(content negotiation)을 통한 뷰 판단과 같은 고유의 REST를 스프링 MVC에서 사용할 수 있다. 클라이언트쪽 REST 지원은 RestTemplate 클래스를 이용할 수 있다.

* 풍부한 고유 포틀릿 2.0 지원: 스프링 MVC는 포틀릿 2.0 환경과 포틀릿 2.0의 새로운 이벤트와 리소스 요청 모델을 지원한다. 일반적인 포틀릿 요청 특징에 따른 구체화된 매핑 기능을 제공한다. @ActionMapping, @RenderMapping, @ResourceMapping, @EventMapping.

* 객체/XML 매핑(OXM): 스프링 웹 서비스에 있었지만, 지금은 스프링 프레임워크 코어로 이동했다. JAXB2, Castor 등을 지원하는 마샬링 언마샬링 추상화를 제공한다. 스프링 MVC와 스프링 JMS에 XML 페이로드(payload) 연동 옵션을 제공한다.

* 차세대 스케줄링 기능: cron을 지원하는 TaskScheduler와 Trigger 매터니즘을 새로 추가했다. 스프링 3.0은 편리한 task 네임스페이스와 @Async, @Scheduled 애노테이션을 제공한다. 고유의 쓰레드 풀 또는 서버가 관리하는 쓰레드 풀에서 실행될 수 있다.

이러한 큰 테마들 이외에, 스프링 2.5에 업그레이드 할 때 특히 좋아할 수백개의 구체적인 개선 사항사항이 있으니 변경사항과 자바독을 확인하기 바란다.

시스템 요구사항에 따르면, 스프링 3.0은 다양한 환경을 다룬다. 두 가지 주요 특징으로, 스프링 3.0은 자바 SE 5 이상서블릿 2.4 이상을 지원한다. 예를 들어 톰캣 5.x와 6.x를 지원한다. 또한 웹스피어 6.1과 웹로직 9.2와 같은 유명한 엔터프라이스 서버와도 호환가능하다. GlassFish v3은 이미 지원하고 있다.

마무리 하자면, 스프링 3는 여러분의 서버를 업그레이할 필요 없이 완전히 새로운 컴포넌트 모델 기능과 JSR-330 주입과 JSR-303 검증같은 표준을 제품 환경에 가져다 준다! 여러분이 해야 할 일은 스프링을 사용중인 애플리케이션의 라이브러리를 스프링 3.0으로 바꾸는 것 뿐이다.

줄겨라 그리고 다음에 이어질 구체적은 스프링 3 기능에 대한 글과 스프링 3.0에서 돌아가는 예제들을 기대하기 바란다!

ps: 반가운 마음에 급하게 번역하느라.. 좀 날림입니다. 이해해 주세요;
신고
top


[스프링 3.0] 스프링 bean과 일반 자바 객체가 호출하는 @Bean 메서드의 차이

Spring/3.0 : 2009.12.11 20:51


public class JavaConfigTest {

    AnnotationConfigApplicationContext ac;

    @Before
    public void setUp(){
        ac = new AnnotationConfigApplicationContext(AppConfig.class);
        assertThat(ac, is(notNullValue()));
    }

    @Test
    public void getBean(){
        SampleBean bean1 = ac.getBean("sampleBean", SampleBean.class);
        SampleBean bean2 = ac.getBean("sampleBean", SampleBean.class);
        assertThat(bean1, is(notNullValue()));
        assertThat(bean2, is(notNullValue()));
        assertThat(bean1, is(bean2));

        AppConfig config1 = new AppConfig();
        SampleBean bean3 = config1.sampleBean();
        assertThat(bean3, is(not(bean2)));

        AppConfig config2 = ac.getBean("appConfig", AppConfig.class);
        SampleBean bean4 = config2.sampleBean();
        assertThat(bean4, is(bean2));
    }

}

스프링 3.0 애노테이션 기반 설정을 익히기 위해서 처음 만들어본 테스트입니다. 이 테스트에서 알 수 있는 건 바로 이 글의 제목에서처럼 @Bean이 붙어있는 메서드를 어떤 객체를 이용해서 호출하느냐에 따라 그 결과가 다를 수 있다는 겁니다.

@Configuration
public class AppConfig {

    @Bean
    public SampleBean sampleBean(){
        return new SampleBean();
    }
}

이건 설정한 빈이고 SampleBean은 뭐 암거나;; @_@;

결론은 new 로 만든 AppConfig와 스프링에서 가져온 AppConfig의 @Bean이 붙은 메서드가 반환해주는 값이다르다는 겁니다. 전자는 일반적인 Java 문맥대로 sampleBean()에서 new SampleBean()으로 새로운 객체를 만들어서 받은 것이고, 후자는 sampleBean() 메서드 호출을 가로채서 기존의 bean을 반환해준 겁니다.

이 경우는 매우 간단한 경우에 속합니다. 하나는 스프링이 관리하는 빈이었고, 하나는 일반 자바 객체였으니까요. 그런데 만약에 둘 다 스프링의 빈이라면? 그 중에 하나는 @Configuration, 다른 하나는 @Component라면?

@Component로 설정한 빈 내부에 위와 똑같은 설정이 들어있다면? 반환하는 객체의 값이 조금 다르나면??

빈 스캔은 어찌하나?

정말 복잡하군요;; 하나씩 차근 차근 해보겠습니다.



신고
top


[스프링 3.0] RC2 릴리즈~

Spring/3.0 : 2009.11.16 22:54


요즘 스프링에 관심이 슬슬 가시기 시작하네요. 벌써 3일이나 지나서야 RC2로 버전을 올리다니.. 예전 같았으면 공개되자마자 버전을 올렸을텐데 말이죠. 하긴.. 뭐 3일 정도 늦었지만, 그래도 봄싹은 아마도 한국에서 가장 빨리 스프링 최신 버전을 적용한 프로젝트가 될 것 같습니다. 후훗

중요 변경 사항을 살펴보겠습니다.

* updated to final versions of JSR-330 "javax.inject" and JSR-303 "javax.validation" APIs
* full compliance with the JSR-330 TCK (i.e. full compliance with the final specification)
* support for Hibernate Validator 4.0 GA (as the JSR-303 reference implementation)
* added support for load-time weaving in JBoss 5.x
* added support for recent EHCache 1.6 configuration properties to EHCacheFactoryBean
* added AnnotatedBeanDefinitionReader helper for programmatic registration of annotated classes
* added AnnotationConfig(Web)ApplicationContext for convenient registration/scanning of classes
* added GenericXmlApplicationContext with flexible configuration options for its XML support
* AbstractApplicationContext can also start up in case of system properties access failure
* internal MergedBeanDefinitionPostProcessors apply after all other post-processors
* inner beans detected as ApplicationListeners as well (only supported for inner singletons)
* child bean definition's scope attribute can be inherited from parent bean definition now
* introduced SmartLifecycle interface with auto-startup and shutdown order support
* introduced LifecycleProcessor delegate, customizable through "lifecycleProcessor" bean
* MessageListenerContainers and Quartz SchedulerFactoryBean start up on refresh instead of init
* added initialize-database tag to jdbc namespace for populating external data sources with data
* PathMatchingResourcePatternResolver leniently ignores non-existing root directories
* DefaultConversionService understands "on"/"off", "yes"/"no", "1"/"0" as boolean values
* CustomEditorConfigurer supports PropertyEditor instances again (with deprecation warning)
* revised MethodParameter's annotation accessor methods
* ClassUtils is now parameterized with Class<?> and Class<T> where appropriate
* DataBinder now accepts var-args to set allowed, disallowed, and required fields
* DataBinder auto-grows nested paths on traversal (avoiding NullValueInNestedPathException)
* fixed enum binding regression with WebRequestDataBinder (as used by @MVC data binding now)
* fixed FieldError to expose rejected input value as String value instead of as array
* JSR-303 Validator will only register validation failures if no binding failure happened
* ContentNegotiatingViewResolver works with ignoreAcceptHeader and defaultContentType as well
* added Spring MVC namespace, with convenient mvc:annotation-driven configuration element
* default number and datetime formatters configured when using the Spring MVC namespace
* full support for datetime formatting using the Joda Time library (automatically enabled)
* added convenient @NumberFormat and @DateTimeFormat annotations for declarative formatting
* implicit T.valueOf(S) and constructor T(S) lookup if no explicit S->T converter matches
* AbstractExcelView is compatible with Apache POI 3.0 as well as 3.5 now
* TilesConfigurer only sets up EL support if JSP 2.1 is present (for JSP 2.0 compatibility)
* re-introduced Struts 1.x support ("org.springframework.web.struts") in deprecated form
* deprecated scheduling support for JDK 1.3 Timer ("org.springframework.scheduling.timer")
* deprecated remoting support for JAX-RPC (in favor of JAX-WS)


신고
top


[스프링 3.0] @Valid 실습

Spring/3.0 : 2009.10.18 12:57


1. 라이브러리 추가.

        <!-- Validation -->
        <dependency>
            <groupId>org.hibernate</groupId>
            <artifactId>com.springsource.org.hibernate.validator</artifactId>
            <version>4.0.0.GA</version>
        </dependency>
        <dependency>
            <groupId>javax.xml.bind</groupId>
            <artifactId>com.springsource.javax.xml.bind</artifactId>
            <version>2.1.7</version>
        </dependency>

2. 빈 설정.

    <bean
        class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter">
        <property name="cacheSeconds" value="0" />
        <property name="webBindingInitializer">
            <bean class="org.springframework.web.bind.support.ConfigurableWebBindingInitializer">
                   <property name="validator" ref="validator" />
               </bean>
        </property>
    </bean>
   
    <bean id="validator" class="org.springframework.validation.beanvalidation.LocalValidatorFactoryBean"/>

3. 애노테이션 기반 검증 설정

    @Column(length = 100)
    @NotEmpty(message="제목을 입력하세요!")
    private String title;
    @Column(columnDefinition="TEXT")
    @NotEmpty(message="제목을 입력하세요!")
    private String contents;

4. 컨트롤러 코드 수정.

    @RequestMapping(value = "/notice/update/{id}", method = RequestMethod.POST)
    public String updateForm(@Valid Notice notice, BindingResult result, SessionStatus status) {
        if (result.hasErrors()) {
            return "notice/update";
        } else {
            noticeService.update(notice);
            status.setComplete();
            return "redirect:/notice/" + notice.getId() + ".do";
        }
    }

끝~!! 기본 에러 메시지는 애노테이션에서 변경할 수 있습니다.

이제 JSR 303 애노테이션과 그 확장 애노테이션에 뭣들이 있는지 살펴봐야겠네요.
신고
top


[스프링 3.0] 애노테이션 기반 스케줄링

Spring/3.0 : 2009.09.28 18:17


참조: http://static.springsource.org/spring/docs/3.0.x/spring-framework-reference/html/ch25s05.html

웹 애플리케이션을 띄울 때 구글 토크 봇을 로그인 시켜두려고 스케줄링을 이용하려 했습니다. 찾아보니까 애노테이션 기반으로 설정할 수 있는 기능이 추가됐더군요.

<task:annotation-driven executor="myExecutor" scheduler="myScheduler"/>

<task:executor id="myExecutor" pool-size="5"/>

<task:scheduler id="myScheduler" pool-size="10"/>}

이렇게 task:annotation-driven 엘리먼트를 XML에 추가해주면 빈에 설정되어 있는 @Schedule과 @Async 애노테이션을 활성화 시켜줍니다.

@Schedule 애노테이션은 cron, fixedDelay, fixedRate 세 가지 속성 중 하나를 이용해서 설정해야 합니다. 반드시 이 셋 중에 하나는 설정되어 있어야 합니다.

@Async 애노테이션은 해당 메서드 호출을 비동기로 처리해주고 싶을 때 사용할 수 있습니다. 즉 이 애노테이션으로 스케줄링이 적용된 메서드를 호출하면 결과는 바로 리턴되고 실제 실행은 스프링의 TaskExecutor에 의해 별도의 Task 내부(이 녀석이 별도의 쓰레드겠죠)에서 실행됩니다.

막상 해보니 라이브러리 때문에 에러가 나더군요.

        <dependency>
            <groupId>edu.emory.mathcs.backport</groupId>
            <artifactId>com.springsource.edu.emory.mathcs.backport</artifactId>
            <version>3.1.0</version>
        </dependency>

그래서 필요한 라이브러리를 추가해주고 돌려보니까 잘 돌아갑니다.

그런데 해보고 나니까 굳이 반복 실행할 필요가 없는 메서드라;;; -_-;; @PostConstruct 애노테이션 붙여서 끝냈습니다.

이 간단한것을... 스캐쥴링은 머하러 찾아봤담;;
신고
top


[스프링 3.0 OXM] 14. Marshalling XML using O/X Mappers 4

Spring/3.0 : 2009.08.20 00:00


참고: http://static.springsource.org/spring/docs/3.0.x/spring-framework-reference/html/ch14s04.html

oxm 네임스페이스를 스프링 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"
    xmlns:oxm="http://www.springframework.org/schema/oxm"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
    http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
    http://www.springframework.org/schema/oxm
    http://www.springframework.org/schema/oxm/spring-oxm-3.0.xsd">

현재 지원하는 태그는 다음과 같다.
    •    jaxb2-marshaller
    •    xmlbeans-marshaller
    •    jibx-marshaller

각각의 태그는 해당 섹션에서 자세히 설명하겠다. 예를 들어, 다음은 JAXB2 마샬러를 설정한 모습니다.

<oxm:jaxb2-marshaller id="marshaller" contextPath="org.springframework.ws.samples.airline.schema"/>

신고
top


[스프링 3.0 OXM] 14. Marshalling XML using O/X Mappers 3

Spring/3.0 : 2009.08.19 23:52


참조: http://static.springsource.org/spring/docs/3.0.x/spring-framework-reference/html/ch14s03.html

14.3 Marshaller와 Unmarshaller 사용하기

다음은 마샬링, 언마샬링에서 사용할 JavaBean이다.

public class Settings {
    private boolean fooEnabled;

    public boolean isFooEnabled() {
        return fooEnabled;
    }

    public void setFooEnabled(boolean fooEnabled) {
        this.fooEnabled = fooEnabled;
    }
}

다음 Application에서는 위의 객체를 settings.xml로 저장하고 다시 그것을 읽어들인다.

import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import javax.xml.transform.stream.StreamResult;
import javax.xml.transform.stream.StreamSource;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.oxm.Marshaller;
import org.springframework.oxm.Unmarshaller;

public class Application {
    private static final String FILE_NAME = "settings.xml";
    private Settings settings = new Settings();
    private Marshaller marshaller;
    private Unmarshaller unmarshaller;

    public void setMarshaller(Marshaller marshaller) {
        this.marshaller = marshaller;
    }

    public void setUnmarshaller(Unmarshaller unmarshaller) {
        this.unmarshaller = unmarshaller;
    }

    public void saveSettings() throws IOException {
        FileOutputStream os = null;
        try {
            os = new FileOutputStream(FILE_NAME);
            this.marshaller.marshal(settings, new StreamResult(os));
        } finally {
            if (os != null) {
                os.close();
            }
        }
    }

    public void loadSettings() throws IOException {
        FileInputStream is = null;
        try {
            is = new FileInputStream(FILE_NAME);
            this.settings = (Settings) this.unmarshaller.unmarshal(new StreamSource(is));
        } finally {
            if (is != null) {
                is.close();
            }
        }
    }

    public static void main(String[] args) throws IOException {
        ApplicationContext appContext =
            new ClassPathXmlApplicationContext("applicationContext.xml");
        Application application = (Application) appContext.getBean("application");
        application.saveSettings();
        application.loadSettings();
    }
}

위에서 설정할 Marshaller와 Unmarshaller는 다음 스프링 설정 파일에서 설정한다.

<beans>
    <bean id="application" class="Application">
        <property name="marshaller" ref="castorMarshaller" />
        <property name="unmarshaller" ref="castorMarshaller" />
    </bean>
    <bean id="castorMarshaller" class="org.springframework.oxm.castor.CastorMarshaller"/>
</beans>

위 설정에서 사용한 Marshaller는 Castor 라이브러리인데, 이 것은 부가적인 설정이 필요 없기 때문에 빈 설정이 간단하다. 도한 CastorMarshaller가 스프링의 Mashaller와 Unmashaller를 모두 구현하고 있다. 따라서 이 빈이 Application의 Marshaller와 Unmashaller에 설정된다. 위 애플리케이션은 다음과 같은 XML 파일을 만들어 낸다.

<?xml version="1.0" encoding="UTF-8"?>
<settings foo-enabled="false"/>


신고
top


[스프링 3.0 OXM] 14. Marshalling XML using O/X Mappers 2

Spring/3.0 : 2009.08.13 18:18


요약, 번역, 참조: http://static.springsource.org/spring/docs/3.0.x/spring-framework-reference/html/ch14s02.html

14.2 Marshaller와 Unmarshaller

14.2.1. Marshaller

스프링은 모든 마셜링 과정을 org.springframework.oxm.Marshaller 인터페이스로 추상화 시켰다. 주요 메서드는 다음과 같다.

public interface Marshaller {

    /**
     * Marshals the object graph with the given root into the provided Result.
     */
    void marshal(Object graph, Result result)
        throws XmlMappingException, IOException;
}

(실제로는 boolean supports(Class<?> clazz)  이것도 있음.)

메서드에 전달받은 Object graph를 javax.xml.transform.Result 객체로 변환해 준다. Result는 태깅 인터페이스로 기본적으로 XML을 추상화한 것이다. 다음과 같은 다양한 구현체들이 있다.

Result implementation    Wraps XML representation
DOMResult    org.w3c.dom.Node
SAXResult    org.xml.sax.ContentHandler
StreamResult    java.io.File, java.io.OutputStream, or java.io.Writer

노트: marshal 메서드가 Object 타입의 객체를 받긴 하지만, 대부분 임의의 객체를 전달하진 않는다. 맵핑 파일에 맵핑한 객체 또는 애노테이션을 표시해둔 객체, 마샬러에 등록한 객체 또는 임의의 상위 클래스를 지닌 객체를 넘긴다. 자세한 내용은 O/X 기술 선택 챕터를 참조하라.

14.2.2. Unmarshaller

Mashaller와 비슷하게 org.springframework.oxm.Unmarshaller 인터페이스도 있다.

public interface Unmarshaller {

    /**
     * Unmarshals the given provided Source into an object graph.
     */
    Object unmarshal(Source source)
        throws XmlMappingException, IOException;
}

(이 녀석도 boolean supports(Class<?> clazz) 이걸 가지고 있음)

javax.xml.transform.Source 타입의 객체를 넘겨주면 Object를 반환해준다. 다음과 같은 Source 구현체들이 있다.
 
Source implementation    Wraps XML representation
DOMSource    org.w3c.dom.Node
SAXSource    org.xml.sax.InputSource, and org.xml.sax.XMLReader
StreamSource    java.io.File, java.io.InputStream, or java.io.Reader

14.2.3. XmlMappingException

스프링은 사용중인 O/X 맵핑 툴의 예외 계층 구조를 XmlMappingExcpetion 계층 구조로 변환해준다. 사용중인 툴이 마샬링과 언마샬링 예외를 구분하고 있지 않더라도,,. 스프링에서 이것을 구분해 준다.


신고
top


[스프링 3.0 OXM] 14. Marshalling XML using O/X Mappers 1

Spring/3.0 : 2009.08.13 18:06


요약, 번역, 참조: http://static.springsource.org/spring/docs/3.0.x/spring-framework-reference/html/ch14.html

14.1 도입

객체/XML 변환 과정, 즉 XML 마샬링(Marshalling) 또는 XML 직렬화(Serialization)에 대해 다룬다.

marshaller는 객체 그래프를 XML로 변환해주고..
unmarshaller는 반대로 XML을 객체 그래프로 변환해 준다.

스프링 OXM을 사용할 때의 장점
- 간편한 설정: JAXB context나 JiBK bidning factory 없이도 간단하게 설정할 수 있다. XML 설정시 oxm 네임스페이스를 제공해준다.
- 일관된 인터페이스: 스프링이 제공하는 Marshaller와 Unmashaller 인터페이스를 사용하면 된다. 클라이언트 코드 변경 없이 O/X 맵핑 프레임워크를 교체할 수 있다.
- 일관된 예외 구조: 제각각인 예외들을 스프링의 XmlMappingExcption 이하의 계층 구조로 변환해 준다. 런타입 예외로 기존의 예외를 감싸기 때문에 에러 정보를 분실하진 않는다.


신고
top


[Spring 3.0] HiddenHttpMethodFilter

Spring/3.0 : 2009.06.10 10:47


어제 밤에 스프링 ROO가 제공하는 REST 코드를 보다가 잠들었는데, 아침에 사부님 댓글을 보니, DELETE와 PUT method를 현재 브라우저와 HTML에서는 완전히 지원하지를 않더군요. 그래서 스프링 레퍼런스를 봤더니 역시나..

org.springframework.web.filter.HiddenHttpMethodFilter

이 녀석을 제공해주고 있었습니다. 사용하는 방법은 간단합니다.

    <filter>
        <filter-name>UrlRewriteFilter</filter-name>
        <filter-class>org.tuckey.web.filters.urlrewrite.UrlRewriteFilter</filter-class>
    </filter>

    <filter-mapping>
        <filter-name>UrlRewriteFilter</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>

이렇게 web.xml에 추가해주면 되죠. 어젯밤엔 졸려서 이부분을 그냥 지나간것 같습니다.

해주는 일은 post method로 넘겨온 파라메터 중에 _method가 가지고 온 값으로 HTTP method를 실제 원하는 method로 바꿔주는 겁니다.

<form:form method="delete">
    <p class="submit"><input type="submit" value="Delete Pet"/></p>
</form:form>

스프링 폼 태그를 이용해서 저렇게 method를 명시해주면 히든 필드 _method에 delete라는 값을 요청에 같이 포함해서 보내주며 실제 보내는 요청은 post가 됩니다. 하지만 이 필터가 _method의 값인 delete를 읽고서 HTTP method를 DELETE로 변경해주고, 그 결과 아래에 있는 핸들러가 이 요청을 처리하게 됩니다.

@RequestMapping(method = RequestMethod.DELETE)
public String deletePet(@PathVariable int ownerId, @PathVariable int petId) {
    this.clinic.deletePet(petId);
    return "redirect:/owners/" + ownerId;
}

REST 스타일을 적용할 때 꼭 필요한 라이브러리 인 듯 합니다.
신고
top


Spring Expression Language(SpEL)

Spring/3.0 : 2009.04.21 17:12


참조: 7. Spring Expression Language (SpEL)

번역, 요약 및 편역 합니다.

7.1 도입

스프링 EL(SpEL)은 실행시(runtime)에 객체 그래프 질의와 조작을 지원하는 강력한 EL(Expression Language)이다. 통합 EL(Unified EL)과 언어 문법이 비슷하지만, 메서드 호출과 기본 문자열 템플릿 같은 추가 기능을 제공한다.

OGNL, MAVEL, JBoss EL 같은 다른 자바 EL도 있지만, 스프링 EL은 스프링 커뮤니티에 모든 스프링 포트폴리오 제품에서 사용할 수 있는 단일 EL을 제공하기 위해 만들었다. 이 언어의 기능은 스프링 포트폴리오의 요구사항을 기반으로 도출했다. 그 중에는 이클립스 기반의 스프링소스 툴 스위트(STS)에서 코드 완성에 필요한 도구도 포함되어 있다.

SpEL이 스프링 포트폴리오에 표현 평가(evaluation) 기반을 제공하기는 하지만, 그렇다고 해서 스프링에 강력하게 묶여있지는 않다. 독립적으로 사용할 수 있다. 독립적으로 사용하는 예제가 이 번 장에 많이 나와있다. 그러려면 약간의 부트스트랩 역할을 하는 (파서 같은)기반 클래스들을 만들어야 한다. 스프링 사용자들은 그런 기반 시설을 사용할 필요가 없고 그저 표현식을 사용하면 된다. 일반적인 SpEL 사용법은 XML 또는 애노테이션 기반 빈 설정에 사용하는 것인데 빈 정의할 때 EL 사용하기 절에서 살펴볼 수 있다.

이번 장은 EL 기능과 API와 그리고 문법을 살펴본다. 

7.2. 기능 개요

EL은 다음의 기능을 제공한다.

      Literal expressions: 상수 표현
      Boolean and relational operators: 불린과 관계형 연산자
      Regular expressions: 정규 표현식
      Class expressions: 클래스 표현식
      Accessing properties, arrays, lists, maps: 속성, 배열, 리스트, 맵에 접근하기
      Method invocation: 메서드 호출
      Relational operators: 관계형 연산자
      Assignment: 대입
      Calling constructors: 생성자 호출
      Ternary operator: 3항 연산자
      Variables: 변수
      User defined functions: 사용자 정의 함수
      Collection projection: 콜렉션 보기
      Collection selection: 콜렉션 선택
      Templated expressions: 템플릿 표현식

7.3. 스프링의 Expression 인터페이스를 사용한 표현식 평가

이번 절에서는 간단한 SpEL 인터페이스와 그 EL 사용법을 살펴보겠다. EL 레퍼런스에서 자세한 내용을 참조하라.

다음 코드는 SpEL API를 사용하여 상수 문자열 표현식 'Hello World' 값을 구한다.

ExpressionParser parser = new SpelAntlrExpressionParser();
Expression exp = parser.parseExpression("'Hello World'");
String message = (String) exp.getValue();

message 변수의 값은 'Hello World'다.

여러분이 주로 사용할 SpEL 클래스와 인터페이스는 org.springframework.expression 패키지와 그 하위 패키지 spel.antlr과 spel.support에 있다.

EL은 ANTLR 문법을 사용하며 lexer와 파서(parser)를 구성할 때 사용한다. ExpressionParser 인터페이스는 표현식 파싱을 책임진다. 이 예제에서 표현식은 홑따옴표로 둘러쌓여있는  문자열 상수다. Expression 인터페이스는 앞에서 정의한 표현식 값을 도출하는 책임을 지니고 있다. parser.parseExpression을 호출할 때는 ParseException이 발생할 수 있고 exp.getValue를 호출할 때는 EvaluationException이 발생할 수 있다.

SpEL은 메서드 호출, 속성 접근, 생성자 호출 같은 다양한 기능을 제공한다.

다음 예제는 메서드 호출의 예로, concat 메서드를 호출한다.

ExpressionParser parser = new SpelAntlrExpressionParser();
Expression exp = parser.parseExpression("'Hello World'.concat('!')");
String message = (String) exp.getValue();

SpEL은 . 기호를 사용하여 속성의 속성에도 접근할 수 있다. 예를 들어 prop1.prop2.prop3에 접근할 수 있고 값을 설정할 수 있다.

ExpressionParser parser = new SpelAntlrExpressionParser();
Expression exp = parser.parseExpression("'Hello World'.bytes.length");  // invokes 'getBytes().length'
int length = (Integer) exp.getValue();

문자열의 생성자도 호출할 수 있다.

ExpressionParser parser = new SpelAntlrExpressionParser();
Expression exp = parser.parseExpression("new String('hello world').toUpperCase()");
String message = exp.getValue(String.class);

여기서 public <T> T getValue(Class<T> desiredResultType) 이 메서드를 주목해서 살펴보자. 이 메서드를 사용하면 결과 값을 캐스팅하지 않아도 된다. 값이 T 타입 또는 등록된 타입 컨버터로 캐스팅이 되지 않을 때는
EvaluationException가 발생한다.

좀 도 흔한 SpEL 사용처는 특정 객체 인스턴스에 대한 표현식일 것이다. 다음 예제는 Inventor 클래스의 인스턴스에서 Name 속성을 가져온다.

// Create and set a calendar
GregorianCalendar c = new GregorianCalendar();
c.set(1856, 7, 9);

//  The constructor arguments are name, birthday, and nationaltiy.
Inventor tesla = new Inventor("Nikola Tesla", c.getTime(), "Serbian");

ExpressionParser parser = new SpelAntlrExpressionParser();
Expression exp = parser.parseExpression("name");

EvaluationContext context = new StandardEvaluationContext();
context.setRootObject(tesla);

String name = (String) exp.getValue(context);

마지막 줄에서 'name' 변수는 "Nikola Tesla"가 설정된다. StandardEvaluationContext 클래스에 "Name" 속성을 찾아볼 객체를 알려준다. 같은 표현식을 새로운 루트 객체로 설정해가며 여러 번 재사용할 수 있다. Expression은 리플렉션을 사용한다.

노트

SpEL을 독립적으로 사용할 때는 파서와 Evaluation context를 만들어야 한다. 하지만 설정 파일의 일부로 SpEL을 사용할 때는 파서와 Evaluation context, root 객체 등을 암묵적으로 스프링이 설정해 준다.

마지막으로 간략히 살펴볼 예제는 불린 연산자를 사용하는 것이다.

Expression exp = parser.parseExpression("name == 'Nikola Tesla'");
boolean result = exp.getValue(context, Boolean.class);  // evaluates to true

7.3.1 EvaluationContext 인터페이스

EvaluationContext 인터페이스는 사용하여 속성, 메서드, 필드를 찾을 수 있고 타입 변환을 수행하는데 이용할 수 있다. 구현하여 제공하는 클래스로 StandardEvaluationContext가 있는데, 객체를 다룰 때 리플렉션을 사용하고, 최적화를 위해 Method, Field, Constructor 인스턴스를 캐싱한다.

StandardEvaluationContext의 setRootObject 메서드를 사용해서 식을 적용할 루트 객체를 명시한다. 또한 setVariable과 registerFunction을 사용하여 표현식에서 사용할 변수와 함수를 명시할 수 있다. 변수와 함수 사용법은 EL 레퍼런스의 변수와 함수 절을 참조하라. StandardEvaluationContext는 또한 커스텀 ConstructorResolver, MethodResolver, PropertyAccessor등을 등록하여 SpEL이 표현식을 다루는 방법을 확장할 수 있다. 자세한 내용은 이들 클래스의 JavaDoc을 참조하라.

7.3.1.1 타입 변환

SpEL은 기본으로 스프링 코어에서 사용할 수 있는 변환 서비스(org.springframework.core.convert.ConversionService)를 사용한다. 이 변환 서비스는 기본 변환기를 내장하고 있지만 커스텀 변환기를 추가하는 것도 가능하다. 또한 핵심 기능으로 제네릭(Generic)을 인식한다. 즉 표현식에서 제네릭 타입을 사용하면, 스프링은 타입 일관성을 유지하기 위해 해당 타입으로 변환을 시도한다는 것이다.

실제로 어떻게 될까? setValue()를 사용하여 문자열을 Boolean 타입의 리스트에 넣는다. SpEL은 해당 리스트의 요소가 Boolean 타입이어야 한다는 것을 인식하고 적절하게 문자열을 Boolean 타입으로 변환해준다.

class Simple {
    public List<Boolean> booleanList = new ArrayList<Boolean>();
}
       
Simple simple = new Simple();

simple.booleanList.add(true);

StandardEvaluationContext simpleContext = new StandardEvaluationContext(simple);

// false is passed in here as a string.  SpEL and the conversion service will
// correctly recognize that it needs to be a Boolean and convert it
parser.parseExpression("booleanList[0]").setValue(simpleContext, "false");

// b will be false
Boolean b = simple.booleanList.get(0);
       
7.4. 빈 정의할 때 EL 사용하기 절

SpEL 표현식은 XML과 애노테이션 기반 설정에서 BeanDefinition에 대한 메타데이터를 정의할 때 사용할 수 있다. 두 경우 모두 표현식을 정의할 때 #{표현식} 문법을 사용한다.

7.4.1. XML 기반 설정

속성 또는 생성자-인자 값을 아래와 같이 표현식에 설정할 수 있다.

<bean id="numberGuess" class="org.spring.samples.NumberGuess">
    <property name="randomNumber" value="#{ T(java.lang.Math).random() * 100.0 }"/>

    <!-- other properties -->
</bean>

'systemProperties' 변수는 미리 정의되어 있다. 따라서 아래 처럼 표현식에서 사용할 수 있다. 미리 정의되어 있는 변수는 #기호를 붙일 필요가 없다.

<bean id="taxCalculator" class="org.spring.samples.TaxCalculator">
    <property name="defaultLocale" value="#{ systemProperties['user.region'] }"/>

    <!-- other properties -->
</bean>

또한 다른 빈의 속성을 그 이름으로 참조할 수도 있다.

<bean id="numberGuess" class="org.spring.samples.NumberGuess">
    <property name="randomNumber" value="#{ T(java.lang.Math).random() * 100.0 }"/>

    <!-- other properties -->
</bean>


<bean id="shapeGuess" class="org.spring.samples.ShapeGuess">
    <property name="initialShapeSeed" value="#{ numberGuess.randomNumber }"/>

    <!-- other properties -->
</bean>

7.4.2. 애노테이션-기반 설정

@Value 애노테이션을 필드, 메서드 그리고 메서드와 생성자의 매개변수에 사용하여 기본 값을 설정할 수 있다.

다음 예제는 필드 변수에 기본 값을 설정한다.

public static class FieldValueTestBean

  @Value("#{ systemProperties['user.region'] }")
  private String defaultLocale;

  public void setDefaultLocale(String defaultLocale)
  {
    this.defaultLocale = defaultLocale;
  }

  public String getDefaultLocale()
  {
    return this.defaultLocale;
  }

}

이번에는 같은 작업을 세터 메서드에 한다.

public static class PropertyValueTestBean

  private String defaultLocale;

  @Value("#{ systemProperties['user.region'] }")
  public void setDefaultLocale(String defaultLocale)
  {
    this.defaultLocale = defaultLocale;
  }

  public String getDefaultLocale()
  {
    return this.defaultLocale;
  }

}

자동 연결(Autowiring)을 사용하는 메서드와 생성자에도 @Value 애노테이션을 사용할 수 있다.

public class SimpleMovieLister {

    private MovieFinder movieFinder;
    private String defaultLocale;

    @Autowired
    public void configure(MovieFinder movieFinder,
                          @Value("#{ systemProperties['user.region'] } String defaultLocale) {
        this.movieFinder = movieFinder;
        this.defaultLocale = defaultLocale;
    }

    // ...
}
public class MovieRecommender {

    private String defaultLocale;
   
    private CustomerPreferenceDao customerPreferenceDao;

    @Autowired
    public MovieRecommender(CustomerPreferenceDao customerPreferenceDao,
                            @Value("#{ systemProperties['user.country'] } String defaultLocale) {
        this.customerPreferenceDao = customerPreferenceDao;
        this.defaultLocale = defaultLocale;
    }

    // ...
}

7.5. EL 레퍼런스

생략

7.6. 예제에서 사용한 클래스

생략



신고
top


What's new in Spring 3.0?

Spring/etc : 2009.04.20 19:34


참조: http://www.epril.com/resources/spring3/reference/html/ch02.html

요약 및 편역합니다.

2.1 자바 5

전페 프레임워크 코드를 제네릭, 가변인수(varargs) 같은 자바 5 기능을 사용하도록 수정했다. FactoryBean, 스프링 AOP, ApplicationListener 코드에 제네릭을 활용했다. 또한, TrasactionCallback과 HibernateCallback과 같은 콜백 인터페이스들은 제네릭한 결과를 반환하도록 수정했다. 스프링 코어 코드베이스를 전반적으로 자바 5에 최적화 시켰다.

스프링의 TaskExecutor 추상화 계층을 자바 5의 java.util.concurrent 시설과 밀접하게 통합되도록 수정했다. JSR-236(자바 EE 6 Concurrency Utilies)에 포함되어 있는 Callable, Future, ExecutorService 어댑터, ThreadFactory 연동 등을 지원한다. 또한 (EJB 3.1 @Asynchronous 또는) @Async 애노테이션을 사용하여 비동기 메서드 호출도 지원한다.

2.2. 개선한 문서

추가된 기능에 맞게 3.0 문서 작업을 새로 했고, 검증을 했지만 그래도 틀린 부분이 있다면 이슈를 등록해 달라.

2.3. 새로운 모듈 구조와 빌드 시스템

다음과 같은 모듈로 새롭게 개정했고 소스 트리당 모듈.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

* 더 이상 모든 구성요소를 담고 있던 spring.jar는 제공하지 않는다.

새로운 스프링 빌드 시스템을 사용한다. 그 시스템은 다음 기능을 제공한다.

      Ivy 기반 "스프링 빌드" 시스템
      일관된 배포 절차
      일관된 의존성 관리
      일관된 OSGi manifest 생성

2.4. 새로운 기능 살펴보기

다음은 스프링 3.0이 새롭게 제공하는 기능이다. 이 기능들을 자세히 살펴보겠다.

      Spring Expression Language
      IoC enhancements/Java based bean metadata
      Object to XML mapping functionality (OXM) moved from Spring Web Services project
      Comprehensive REST support
      @MVC additions
      Declarative model validation
      Early support for Java EE 6

2.4.1. 자바 5에 맞게 핵심 API 업데이트

BeanFactory 인터페이스가 타입에 맞는 빈을 반환한다.

      T getBean(Stringname, Class<T> requiredType)
      Map<String, T> getBeansOfType(Class<T> type)

스프링의 TaskExecutor 인터페이스가 java.util.concurrent.Executor를 상속 받는다.

      AsyncTaskExecutor를 확장하여 표준 Callables와 Futures를 지원한다.

새로운 자바 5 기반의 converter API와 SPI
 
      stateless ConversionService와 Converters
      표준 JDK PropertyEditor 대체제

타입을 가지고 있는 ApplicationListener<E>

2.4.2. 스프링 EL(Expression Language)

스프링은 통합 EL과 비슷한 EL을 토입했다. EL은 XML 정의와 애노테이션 기반 빈 설정에서 사용할 수 있다. 이 기능에 대한 자세한 설명은 Spring Expression Language (SpEL).장을 참조하라.

스프링 EL은 모든 스프링 포트폴리오 제품에서 사용할 수 있는 단일 EL을 제공하기 위해 만들었다.

다음은 데이터베이스 설정 프로퍼티에 EL을 사용하는 예제다.

<bean class="mycompany.RewardsTestDatabase">
    <property name="databaseName"
        value="#{systemProperties.databaseName}"/>
    <property name="keyGenerator"
        value="#{strategyBean.databaseKeyGenerator}"/>
</bean>

이 기능은 애노테이션에도 사용할 수 있다.

@Repository
public class RewardsTestDatabase {

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

    @Value("#{strategyBean.databaseKeyGenerator}")
    public voidsetKeyGenerator(KeyGenerator kg) { … }
}

2.4.3. IoC 컨테이너

2.4.3.1. 자바 기반 빈 메타데이타

JavaConfig 프로젝트의 몇몇 핵심 기능을 스프링 프레임워크로 가져왔다. 즉 다음의 애노테이션을 직접 사용할 수 있다는 뜻이다.
   
      @Configuration
      @Bean
      @Primary
      @Lazy
      @Import
      @Value

다음은 JavaConfig 기능을 사용하는 기본적인 빈 설정 예제다.

@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() {
        // wire up a session factory using
        // AnnotationSessionFactoryBean
        asFactoryBean.setDataSource(dataSource());
        return (SessionFactory) asFactoryBean.getObject();
    }

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

이 것이 동작하게 하려며 애플리케이션 컨텍스트 XML 설정 파일에 다음과 같이 컴포넌트 스캔을 추가한다.

<context:component-scan
    base-package="com.myco.config"/>
 
2.4.3.2. 애노테이션을 활용한 팩토리 빈 정의

FactoryBean은 스프링 컴포넌트 정의와 표준 컴포넌트-스캔 기술을 사용한 등록 방식으로 정의할 수 있다. 자세한 내용은 Factory Bean Definitions using annotations을 참조하라.

2.4.4. Data 단

스프링 웹 서비스 프로젝트에서 객체(Object)를 XML로 맵핑하는 기능(OXM)을 스프링 프레임워크로 가져왔다, 이 기능은 org.springframework.oxm 패키지에 들어있다. OXM의 자세한 사용법은 Marshalling XML using O/X Mappers를 참조하라.

2.4.5. Web 단

웹 단에서 가장 흥미로운 새 기능은 RESTful 웹 서비스와 웹 애플리케이션 지원 기능이다. 또한 새로운 애노테이션도 사용할 수 있다.

2.4.5.1. 방대한 REST 지원

RESTful 애플리케이션을 만드는 서버쪽 지원은 기존의 MVC 웹 프레임워크에서 주도적인 역할을 하는 애노테이션에 대한 확장 기능으로 제공한다. 클라이언트쪽 지원은 RestTemplate 클래스로 제공한다. 이 둘 모두 HttpConverter를 사용하여 객체와 그것에 대한 HTTP 요청과 응답 사이를 변환 해준다.

MarhsallingHttpMessageConverter는 앞서 언급한 Object to XML 맵핑 기능을 사용한다.

자세한 내용은 REST support를 참조하라.

2.4.5.2 @MVC additions

@CookieValue와 @RequestHeaders 애노테이션이 추가됐다. Mapping cookie values with the @CookieValue annotationMapping request header attributes with the @RequestHeader annotation을 참조하라.

2.4.6 선언적인 모델 검증

하이버네이트 검증기, JSR 303

작업중... 스프링 3.0 M3 배포에 포함되어 있지 않다.

2.4.7 발빠른 자바 EE 6 지원

새로운 애노테이션 @Async (or EJB 3.1's @Asynchronous 애노테이션)을 사용하여 비동기 메서드 호출을 지원한다.

JSF 2.0, JPA 2.0, 기타 등등

작업중... 스프링 3.0 M3 배포에 포함되어 있지 않다.


신고
top


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



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

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


신고
top


REST in Spring 3: @MVC

Spring/etc : 2009.03.09 11:10


참고: REST in Spring 3: @MVC

스프링 3.0의 RESTful 기능

- URI 템플릿
@PathVariable 애노테이션으로 URI의 특정 위치의 값을 맵핑해올 수 있음.
@RequestMapping("/hotels/{hotelId}")
public String getHotel(@PathVariable hotelId, ModelMap model) {
  List<Hotel> hotels = hotelService.getHotels();
  model.addAttribute("hotels", hotels);
  return "hotels";
}
이때 /hotels/1 이런 요청이 들어오면 hotelId 매개변수로 1이라는 값을 받아올 수 있음.

두 개 이상 맵핑 할 수도 있고 변수명을 다르게 줄 수도 있음.
@RequestMapping(value="/hotels/{hotel}/bookings/{booking}", method=RequestMethod.GET)
public String getBooking(@PathVariable("hotel") long hotelId, @PathVariable("booking") long bookingId, ModelMap model) {
  Hotel hotel = hotelService.getHotel(hotelId);
  Booking booking = hotel.getBooking(bookingId);
  model.addAttribute("booking", booking);
  return "booking";
}

Ant 스타일 경로를 지정할 수도 있음.
@RequestMapping(value="/hotels/*/bookings/{booking}", method=RequestMethod.GET)
public String getBooking(@PathVariable("booking") long bookingId, ModelMap model) {

}

데이터 바인딩도 사용할 수 있음.
@InitBinder
public void initBinder(WebDataBinder binder) {
  binder.initBeanPropertyAccess();
  SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");
  dateFormat.setLenient(false);
  binder.registerCustomEditor(Date.class, new CustomDateEditor(dateFormat, false));
}

@RequestMapping("/hotels/{hotel}/dates/{date}")
public void date(@PathVariable("hotel") String hotel, @PathVariable Date date)
                throws IOException {

}
/hotels/1/dates/2008-12-18 이런 요청을 받으면 2008-12-18 이 부분 문자열을 Date 타입으로 바인딩 해 줌.

- Content Negotiation
Accept HTTP 헤더로 뷰를 판단함. 서버 응답은 Content-Type를 통해 뷰를 전달한다. 이런 과정을 content negotiation이라고 한다.

주요 클래스: ContentNegotiatingViewResolver

- Views
RSS 피드를 만들 때 사용할 수 있는 뷰: AbstractAtomFeedView, AbstractRssFeedView
XML 뷰: MarshallingView
JSON 뷰: JacksonJsonView

- HTTP Method Conversion
HTTP에서는 GET, POST, DELETE, PUT을 제공하지만 HTML은 GET, POST만 지원한다. 따라서 POST를 사용하면서 hidden parameter로 Method를 명시하면 해당 Method로 변환해주는 HiddenHttpMethodFilter 제공.
스프링 form 태그에서 이 기능을 지원하기 때문에 form태그의 method에 delete, put도 사용 가능.
<form:form method="delete">
    <p class="submit"><input type="submit" value="Delete Pet"/></p>
</form:form>

@RequestMapping(method = RequestMethod.DELETE)
public String deletePet(@PathVariable int ownerId, @PathVariable int petId) {
    this.clinic.deletePet(petId);
    return "redirect:/owners/" + ownerId;
}

- ETag support
ETga는 HTTP 1.1 호환 응답 헤더로 해당 URL에 있는 컨텐츠가 변경 됐는지 확인할 때 사용.
스프링은 ShallowEtagHeaderFilter를 제공하여 JSP로 랜더링한 결과를 캐싱하고 MD5 해시를 만들고 응답에 ETag를 반환해준다. 다음에도 사용자가 같은 자원을 요청하면 이전에 만든 해시를 If-None-Match 값으로 사용한다. 두 개 해시값을 비교해서 같으면 304(Not Modified)를 반환한다.

차후에 제공할 deep ETag는 모데인 객체나 RDBMS 테이블과 관련되어 있어 좀 더 복잡한데 JPA의 @Version(낙천적-롹킹할 때 사용하는 애노테이션) 기반 또는 ApsectJ의 애스팩트로 지원할 예정~ 이라고 합니다.
신고
top


Petclinic을 통해 스프링 3.0 주요기능 살펴보기

Spring/etc : 2009.02.26 10:09


Spring Framework 3.0 M2 released

스프링 3.0 m2가 배포됐습니다. 유겐 휄러가 주요 기능을 잘 정리해 뒀네요. 아쉬운건 아직도 레퍼런스 업데이트가 되지 않았다는 겁니다. 어쩔 수 없이 아쉬운 사람이 우물 판다고 예제 코드를 뒤적거릴 수밖에 없더군요.

EL 지원에 관한 예제는 petclinic-servlet.xml에서 볼 수 있습니다.

    <bean id="visits" class="org.springframework.samples.petclinic.web.VisitsAtomView"/>

    <bean id="vets" class="org.springframework.web.servlet.view.xml.MarshallingView">
        <property name="contentType" value="application/vnd.springsource.samples.petclinic+xml"/>
        <property name="marshaller" ref="marshaller"/>
    </bean>

    <bean class="org.springframework.web.servlet.view.ContentNegotiatingViewResolver">
        <property name="mediaTypes">
            <map>
                <entry key="xml" value="#{vets.contentType}"/>
                <entry key="atom" value="#{visits.contentType}"/>
            </map>
        </property>
        <property name="order" value="0"/>
    </bean>

이렇게 visits와 vets 빈의 contentType 속성에 들어있는 값을 #{vets.contentType}, #{visits.contentType} 이런식으로 참조하여 다른 빈에 주입할수 있습니다. visits에는 contentType속성이 없는 것 같지만 이 속성은 AbstractView에 있는 속성이고 VisitsAtomView 클래스가 그것을 상속했기 때문에 기본값을 가지게 될 겁니다.

다음으로 RestTemplate 기능은 컨트롤러에서 볼 수 있습니다.

@Controller
@RequestMapping("/owners/{ownerId}/pets/new")
@SessionAttributes("pet")
public class AddPetForm {
...
    @RequestMapping(method = RequestMethod.GET)
    public String setupForm(@PathVariable("ownerId") int ownerId, Model model) {
        Owner owner = this.clinic.loadOwner(ownerId);
        Pet pet = new Pet();
        owner.addPet(pet);
        model.addAttribute("pet", pet);
        return "pets/form";
    }
...
}

이런 식으로 URL의 일부를 매서드 매개변수로 바인딩 해줍니다. 바인딩 할 필요가 없는 경우 와일드 카드를 이용할 수도 있습니다.

@Controller
@RequestMapping("/owners/*/pets/{petId}/visits/new")
@SessionAttributes("visit")
public class AddVisitForm {
...
    @RequestMapping(method = RequestMethod.GET)
    public String setupForm(@PathVariable("petId") int petId, Model model) {
        Pet pet = this.clinic.loadPet(petId);
        Visit visit = new Visit();
        pet.addVisit(visit);
        model.addAttribute("visit", visit);
        return "pets/visitForm";
    }
...
}

이런 식으로 말이죠. 간단해 보이네요~

다음으로는 AtomView 지원 기능도 살펴봤습니다. 3.0에 추가된 AbstractAtomFeedView 이 클래스를 상속해서 구현하면 되더군요.

public class VisitsAtomView extends AbstractAtomFeedView {
...
    @Override
    protected void buildFeedMetadata(Map<String, Object> model, Feed feed, HttpServletRequest request) {
...
    }

    @Override
    protected List<Entry> buildFeedEntries(Map<String, Object> model,
            HttpServletRequest request, HttpServletResponse response) throws Exception {
...
    }
   
}

구현은 이런 식이며 피드 메타 데이터는 Feed 객체에 Id와 Title을 그리고 Updated에 날짜를 채워줍니다. 코드에 에러가 있어서 Feed 라는 클래스를 자세히 보지 못해서 아쉽네요. 그 아래 매서드에서는 Entry List를 만들어서 반환해줍니다. Entry도 역시 자세히 보고 싶은데 못봤습니다. id, title, updated, summary 정보를 설정하는 코드로 대충 어떤 속성이 있는지 예상할 순 있었습니다.

마지막으로 OXM 기능을 살펴봤는데 끝내주더군요. @_@

    <bean id="vets" class="org.springframework.web.servlet.view.xml.MarshallingView">
        <property name="contentType" value="application/vnd.springsource.samples.petclinic+xml"/>
        <property name="marshaller" ref="marshaller"/>
    </bean>

    <oxm:jaxb2-marshaller id="marshaller">
        <oxm:class-to-be-bound name="org.springframework.samples.petclinic.Vets"/>
    </oxm:jaxb2-marshaller>

보시다시피 MarshallingView는 스프링 3.0에서 제공하는 클래스고 Vets는 도메인 클래스입니다. OXM을 지원하는 스키마까지 제공하는군요. 저렇게만 설정하면 객체를 알아서 XML로 변환해주느냐???... 아니요 한가지 더 필요합니다.

 @XmlRootElement
public class Vets {

    private List<Vet> vets;

    @XmlElement
    public List<Vet> getVetList() {
        if (vets == null) {
            vets = new ArrayList<Vet>();
        }
        return vets;
    }

}

캬... 뭐 대충 눈으로 보면 뭐하는건지 알 수 있게해주는 직관적인 코드입니다.

자 이정도면 대충 주요 기능은 거의다 조금 살펴본 것 같습니다. 예제 코드좀 돌려보면 좋겠는데 그건 나중에 해봐야겠습니다. 지금은 번역 땜시..-_-;;



신고
top


스프링 프레임워크 3.0 m1 임박.

Spring/etc : 2008.11.29 13:36


참조: http://jira.springframework.org/browse/SPR?report=com.atlassian.jira.plugin.system.project%3Aroadmap-panel

아마도 S1A 컨퍼런스에 맞춰서 하나 공개하고 싶었는지 이슈를 뒤로(m2)좀 미룬거 같습니다. 캬오..

눈에 띄는 이슈 몇 가지는 흠..
- 내부 코드를 자바 5 기반으로 업그레이드
- @RequestMapping에서 URI 템플릿 기능 제공
- RSS/ATOM 뷰 지원
- @RequestParam에 defaultValue 속성 추가
- Expression Language Support(모르겠음)

흠.. REST는 m2에 추가되지만 이번에 추가되는 기능 중에 URI 템플릿 기능과 RSS 지원 기능 그리고 @RequeestParam에 defaultValue 속성 추가는 당장 개발에 써먹을 수 있어 보입니다. 하나 더 EL 기능에 대한 건 잘 파악이 안 됐는데 저게 JSF를 지원하는 기능인건지.. 아님 빈 XML 설정 파일에서 EL을 쓸 수 있게 해주겠다는 건지 좀 햇갈리네요. 자세히 봐야겠습니다.
신고
top


Spring 2.5 on the Way to 3.0 - 유겐 휄러



참조 : Spring 2.5 on the Way to 3.0

Spring One 2008에서 유겐 휄러의 발표 동영상을 보여줍니다. 별점은. 3.2/5 정도 됩니다. 지난 번에 봤던 Using Spring Security (별점 4/5)보다 평점이 조금 낮네요.

JDK 6 지원
- JDK 1.4, 1.5 호환(1.3은 안 함)
- JDBC 4.0 지원(native connections, LOB 핸들링)
- JMX MXBenas

AspectJ LTW 지원

Java EE 5 지원

JSR-250 애노테이션 지원
- @PostConstruct, @PreDestroy
- @Resource
- self describing.

Further Java EE 5 Annotations
- @WebServiceRef/@EJB
- @TransactionAttrubute
- @PersistenceContext/@PersistenceUnit

Autowiring Annotation
- specific autowiring by type
- @Qualifier

Autodetectable Component
- @Component

@Configurable with AspectJ
- <context:load-time-weaver aspectj-weaving="on" />
- <context:spring-configured />
- @Configurable

@Transactional with AspectJ
- <context:load-time-weaver aspectj-weaving="on" />
- <tx:annotation-driven mode="aspectj" />

Annotated MVC Controllers
- @Controller
- @RequestMapping
- @RequestParam
- @ModelAttribute

Test Context Framework
- @ContextConfiguration
- @TransactionConfiguration
- JUnit 4.4 지원.

Tradeoffs
- 재컴파일(XML 설정 변경은 재컴파일 필요 없다.)
- 설정의 외부화(애노테이션은 클래스를 보면 내용을 알 수 있다.)
- 설정 재정의 가능 여부(애노테이션 설정 바꾸면 컴파일 필요하다.)

Spring 2.5 정리
- Java 5와 Java EE 5 완전 지원
- ApsectJ와 보다 긴밀한 연동
- 애노테이션 설정 강화

The Roadmap for Spring 3.0
- 7월까지 2.5.6
- 8월에 3.0 M1
  - REST 지원
  - 다양한 EL 지원
- Spring 3.0 GA는 4분기 중으로..
=> 흠.. 이미 8월 지난지 오래 됐는데, M1 소식도 못들었네요. 내년 초를 기대해봐야겠네요.

Spring 3: Core Revisions
- Java 5+ 지원
  - 스프링 코어 API에 Generic 적용
- J2EE 1.4+ 호환(웹스피어 6.1, 웹로직 9.2, JBoss 4.2)
- 스프링 EL
- 새로운 커테이너 기능 제공(annotated factory methods)
=> 흠. 제레닉 코드가 코어 API에 들어가면.. 혹시 GenericDAO 같은 거도 스프링이 제공하는건가.. 캬오..

Spring 3 and the Web Space
- 개정된 자바 웹 표준 지원(포틀릿 2.0, 서블릿 3.0)
- REST 지원
- conversation 관리
- 애노테이션 기반 위자드 컨트롤러
=> 스프링 3이 conversation이랑 애노테이션 기반 위자드 마법사를 지원해주면.. 캬오 멋질듯.

Spring 2.5 Mission Continued

Pruning & Deprecation in 3.0
- 가지칠것
  - Commons Attuributes 지원
  - 예전 TopLink API 지원
- deprecation 계획
  - 예전 MVC 컨트롤러 클래스 계층 구조
  - 예전 JUnit 3.8 테스트 클래스 계층 구조
=> 애노테이션 기반 시설 중심으로 가면서 예전 시설은 deprecation.

Spring 3.0 Summary
- REST, EL
- RESTful URI 맵핑, 포틀릿 2.0
- Java 5+, Spring 2.5 환경에서 그대로 호환 가능.

아음.. 발표 시간이 64분인데, 55분동안 2.5 얘기만 하다가 3.0 얘기는 빠르게 지나가 버려서 아쉽습니다. 그래서 별 세개만 줬어요. ㅋㅋ 유겐 횽님 Spring One America에서는 스프링 3.0 얘기 좀 더 해주세요. ㅠ.ㅠ 소스도 배포해 주시구요. 3.0에서 저는 컨버세이션 관리와 위자드 마법사가 제일 궁금해요. 그 다음으로는 코어 API에 추가할 제네릭 클래스들 중에 GenericDao같은 것들도 제공할 것인지도 궁금하구요. 마지막으론 스프링 EL도 궁금한데.. 그건 JSF 확장 기능이겠죠? JSP에서도 사용 가능한건가? 어쨋든 S1A에서 뵙겠습니다. 바이바이
신고
top







티스토리 툴바