티스토리 툴바



'Spring 지식 공유하기'에 해당되는 글 131건

  1. 2010/07/24 Spring Explorer 잘 쓰기
  2. 2010/06/04 [Spring 3.0 Inside] 3. RESTful MVC
  3. 2010/05/25 [Spring 3.0 Inside] 2. Formatter
  4. 2010/05/20 [Spring 3.0 Inside] 1. ConversionService
  5. 2010/05/11 BeanPostProcessor 구현 시 주의할 점
  6. 2010/03/22 Bean Validator 확장 방법
  7. 2010/02/22 스프링 3.0 체인지 로그 분석 - Spring 3.0 RC2 ~ GA
  8. 2010/02/03 테스트 컨텍스트 프레임웍의 스테레오 타입 종류와 범위
  9. 2010/01/19 스프링 3.0 체인지 로그 분석 - Spring 3.0 RC1
  10. 2010/01/11 스프링 3.0 체인지 로그 분석 - Spring 3.0 M4
2010/07/24 12:10

Spring Explorer 잘 쓰기

Spring IDE를 설치하면 기본적으로 제공하는 뷰 중에 하나로 'Spring Explorer'가 있습니다.
하지만 일반적으로는 잘 사용하지 않습니다. 정확히 말하자면 개발 중에 그렇게 볼 필요가 없다는 겁니다.

그러나 빈 설정을 애노테이션으로 하기 시작하면서 얘기가 조금 달라졌습니다.
빈 설정을 애노테이션으로 하거나, Autowiring을 위주로 사용하보니 명시적으로 의존성을 관리할 때에 비해서 직접 테스트나 시스템을 띄우기 전까지는 의존성 관계가 정상적으로 되었는지 확인하기가 어렵다는 겁니다. 어떨때는 시스템을 띄워서 에러 메세지를 보고도 바로 파악하지 못하고 해매는 경우도 발생합니다.

방금 전 강의에서도 한 분이 패키지가 다른 위치에 있는 빈인지 모르고 특정 빈(컨트롤러)가 왜 매핑이 안되는지 한참을 찾는 경우가 발생했습니다. 의존성 주입인 경우에는 그나마 나은데 이번에는 컨트롤러다 보니 의존성 주입 실패가 아니라 웹 요청이 매핑되는 핸들러가 없다고 하니 이 부분ㅇ르 바로 캐치하지 못하신 거였죠. 더군다나 빈의 갯수가 많아지면 더 힘들겠죠.

이럴 때 Spring Explorer를 활용해 실제로 시스템이 올라갈 때 등록되는 빈들을 미리 확인할 수가 있습니다. 위의 분의 경우에도 Spring Explorer을 보고 나서 바로 빈이 올라가지 않아서 그렇다는 상황을 바로 알아낼 수가 있었습니다.

상황을 공유하려고 간략히 쓰려고 했는데 조금 길어졌군요..;


저작자 표시 비영리
크리에이티브 커먼즈 라이선스
Creative Commons License
Trackback 0 Comment 0
2010/06/04 15:26

[Spring 3.0 Inside] 3. RESTful MVC

# Rest URL 매핑 지원
@RequestMapping과 @PathVariable 등을 통해 Restful 스타일의 URL 매핑 기능을 지원합니다.
JAX-RS 구현체와 기존 Spring MVC를 연계하여 Restful한 서비스를 구성할 수 있지만, 3.0에서는 @MVC를 사용하여 직접 restful한 서비스를 구현할 수 있는 기능을 제공합니다. 이 둘간의 비교는 이 링크 http://www.infoq.com/articles/springmvc_jsx-rs를 참조하시면 됩니다.

# Contents negotiation
HTTP Accept 헤더로 서버 응답(view)을 내리는 방법을 결정합니다. 실제로는 ContentNegotiatingViewResolver을 통해서 구현되어 있습니다.
HTTP Accept 헤더를 기준으로 판단하여 다른 viewresolver를 결정하며, context 내의 view resolver를 자동으로 찾도록 할 수도 있고, 명시적으로 설정도 가능합니다. 
주의할 점은 view resolver order 상 가장 위로 해주어야 합니다. view resolver는 view를 결정하는 방법이지 view 자체가 아니므로 controller에서 이 resovler를 쓴다고 해서 따로 해야할 일은 없습니다. 
Contents negotiation 뿐만 아니라 웹 파라미터를 통해 뷰를 결정하거나, url의 확장자를 통해 뷰를 결정하는 기능을 뷰 리졸버 확장을 통해서 구현할 수도 있습니다. 다양한 RESTful URL 매핑 방식을 구성할 수 있습니다.
또한 그리고 Restful한 서비스를 구현할 때 뿐만 아니라 다양한 클라이언트 솔루션과의 연계에서도 ViewResolver를 통한 뷰를 런타임시에 결정하는 방식을 응용할 수가 있습니다.

# ETag
해당 URL의 컨텐츠가 변경 되었는지 결정하는데 사용하는 HTTP/1.1 호환 웹 서버 반환 HTTP 응답 헤더를 말하며, 헤더의 If-None-Match 비교합니다. 크게 두 가지 방식으로 구현이 가능한데 shallow tag과 deep tag 방식이 있습니다. 

스프링에서 shallow tag 방식을 제공하며, 구현하는 방식은 응답을 내려보낼 때 md5 해시 값을 저장해두었다가 다음 번에 동일한 리소스에 대한 요청이 올 때도 역시 md5를 구해봐서 이 값이 같으면 "304:Not Modified"를 반환하게 됩니다. (ShallowEtagHeaderFilter를 통해 구현) 이렇게 처리함으로써 동일한 자원을 렌더링하는 시간을 줄일 수가 있겠죠. 렌더링 시간을 동일하나 클라이언트로 반환하는 컨텐츠를 없애서(contentlength=0) bandwidth를 줄여주게 됩니다.
deep etag는 이런 비교의 기준을 도메인 객나 rdb 테이블 등에 저장해 처리하며. 이는 차후 스프링 버전에서 지원할 예정이라고 합니다.(JPA의 @Version 처럼...)

그러나 위키피디아를 찾아보니 shallow, deep tag라는 용어를 사용하지는 않네요. 그 대신 collision-resistant hash function을 주로 활용한다고 하고, 오히려 optimistic concurrency control을 구현하는데 ETag를 활용할 수 있다는 게 더 관심이 가는 내용입니다.

# HTTP 메서드 풀 지원 HTTP Method Conversion
html에서는 get/post만 지원하는데 스프링에서는 전체 HTTP 메서드를 지원하는 필터(HiddenHttpMethodFilter)를 제공합니다. HiddenHttpMethodFilter를 등록함으로써 HTML에서도 전체 HTTP 메서드를 사용해 RESTful 서비스를 구성할 수가 있습니다.

# 다양한 view 지원
3.0에서는 크게 JSON, XML, RSS에 대한 별도의 뷰가 추가되었습니다.
- MarshallingView: 다양한 파싱구현체 지원은 좋으나 지금까지는 단 하나의 모델엘 대한 매핑 기능만 제공하는 단점이 있습니다.
- JacksonJsonView: Jackson API를 사용하여 DTO와 JSON 객체와의 매핑 기능 제공
- AbstractAtomFeedView, AbstractRssFeedView: FEED를 뷰로 구성할 수 있는 추상 클래스를 제공. 클래스를 상속해 필요한 메서드를 재정의하면 됨.

그 외 클라이언트 수준의 REST API를 지원하는 RestTemplate을 제공합니다만 생략하도록 하겠습니다^^.
저작자 표시 비영리
크리에이티브 커먼즈 라이선스
Creative Commons License
Trackback 0 Comment 0
2010/05/25 13:15

[Spring 3.0 Inside] 2. Formatter

Formatter는 사실상 Conversion 서비스의 한 분류로 볼 수 있습니다.
둘 간의 관계는 조금 오묘한데..

Conversion은 general한 타입 변환이 목적이며, 예를 들면 Date <-> Long 간의 변환이 있습니다.
반면에 Formatter는 동일한 타입 내에서 타입의 '포맷'을 변환하는 목적으로 사용하며, String localizing를 예로 들 수 있습니다.

아래 설명하겠지만 Formatter는 내부적으로 Conversion의 Converter로 변환되어 Conversion의 서비스와 동일한 시점에 사용됩니다.

# 구현
Formatter가 상속하는 인터페이스가 Printer와 Parser로 나뉘어 있습니다.

Printer에 정의된 print(..)는 해당 객체에 대한 출력 시 필요한 변환 로직을 작성하며, Parser에 정의된 parse(..)는 문자열(String)이 들어 왔을 때 해당 타입의 객체로 변환해주는 로직을 구현하게 됩니다.
public interface Formatter<T> extends Printer<T>, Parser<T> {
}
public interface Printer<T> {
    String print(T fieldValue, Locale locale);
}
public interface Parser<T> {
    T parse(String clientValue, Locale locale) throws ParseException;
}
포매터는 크게 날짜 관련 포매터와 숫자 관련 포매터로 나뉘어 있습니다.

# 사용
내부적으로 사용 시에는 Formatter 인터페이스가 아닌 Printer와 Parser 각각의 인터페이스 타입으로 사용 됩니다.
이 또한 직접 호출하지 않으며 각각을 래핑하고 있는 Converter를 통해서 호출 되며, 각각Printer=PrinterConverter, Parser=ParserConverter로 매핑됩니다. 이들은 GenericConverter 인터페이스를 구현하고 있죠.
결국 Converter와 동일한 시점에 동일한 방식으로 호출된다는 의미입니다!

애노테이션 방식으로 구현 시 제공되는 애노테이션은 @DateTimeFormat과 @NumberFormat 두 가지가 있습니다.
@DateTimeFormat은 정해진 예약어를 통해 스타일 지정 가능하며, "S"=short, "M"=medium, "L"=long, "F"=full과 같은 식입니다. 기본 구분자는 "-"입니다.(변경이 가능하지 모르겠네요?)

@NumberFormat에서 style()은 해당 숫자의 유형(일반 숫자, 퍼센트, 통화)을 가리키며, 각 스타일마다 내부 상수로 유지하고 있습니다.

# 설정
포매터들에 대한 목록은 FormatterRegistry 인터페이스를 통해 등록되며, 이 인터페이스 FormattingConversionService이 구현하고 있습니다.

Converter들은 FormattingConversionService을 통해 등록 합니다. FCS는 FormatterRegistry 인터페이스를 구현하면서 동시에 GenericConversionService을 상속하죠. 이 클래스는 Formatter를 받아 Converter로써 ConversionService에 등록해주는 역학을 합니다.

애노테이션 기반일 경우에는 AnnotationFormatterFactory을 통해서 각 애노테이션에 맞는 Parser와 Printer가 생성 됩니다.
Date 타입에 관련된 Formatter의 경우 Parser와 Printer가 각각의 구현 클래스를 통해 제공하니 직접 Formatter 인터페이스를 구현하지는 않았습니다.Number 타입의 경우 숫자의 유형(일반 숫자, 퍼센트, 통화)에 따라 Formatter가 생성 됩니다. Parser와 Printer로 나누어 생성되지는 않네요..(NumberFormatAnnotationFormatterFactory 참조)

이 때 각각의 포맷 팩토리와 포매터에 대한 컨버전 서비스는 FormattingConversionServiceFactoryBean를 통해서 자동 등록 됩니다. 실제로는 InitializingBean.afterPropertiesSet() 메서드 내에서 초기화됩니다. 
또는 더 간단히 mvc에서는 <mvc:annotation-driven />을 통해서 등록 할 수 있습니다.

저작자 표시 비영리
크리에이티브 커먼즈 라이선스
Creative Commons License
Trackback 0 Comment 0
2010/05/20 12:55

[Spring 3.0 Inside] 1. ConversionService

20100520 갱신: 적용 대상 추가 및 정리
=============================================

Spring 3.0에 와서는 많은 내용이 추가되고 개선되었습니다. 그만큼 내부 구현 코드도 많은 부분이 변경되었습니다. 
단순히 Java 5 문법이 코드 베이스에 추가된 것 외에도 말이죠.. 그런 의미에서 다시 한 번 스프링 내부 코드를 보면서 정리하고 있는 데 그간 정리한 내용은 더 간단히 기술해 공유하도록 하겠습니다.
(ps. 제가 이해하기 위해 정리한 내용을 요약해 공개하는 것이므로 설명이 다소(?) 짧고 난해할 수도 있으니 이해해주세요^^)

# 타입 변환 시나리오 및 변환 수행
일반적으로 타입 변환 요건이 발생하는 상황이 있습니다.

1. 웹의 파라미터로 넘어오는 String 값을 DTO에 바인딩 시 (DataBinder)
2. XML의 value 속성의 값을 해당 빈 클래스의 프로퍼티로 매핑 시
3. 직접 BeanWrapper를 통해 빈을 다룰 때
4. EvalTag 
5. SpEL

타입 변환이 일어나는 상황은 다양하지만 내부 로직을 타고 들어가다 보면 실제로 타입 변환은 TypeConverterDelegate에서 수행됩니다. 이 클래스는 BeanWapperImpl이나 SimpleTypeConverter와 같은 클래스에 멤버로 선언되어 있고, 이들 클래스에 설정된 ConversionService를 넘겨 받아서실제로 타입 변환 요청이 들어오게되면 타입 변환을 시도 합니다.

제가 처음에 ConversionService가 도입 됐다는 말을 듣고 의문이 들었던 점은 "그럼 기존에 PropertyEditor 기반 변환은 어떻게 된건가?"였습니다. 하위 호환성 보장을 해야 하니까요..

이런 궁금즘은 TypeConverterDelegate.convertIfNecessary()을 살펴보고나서 해결됐습니다. 실제로는 이 메서드 내에서 순차적으로 변환을 시도 합니다.
순서는 
1. ConversionService를 이용할 수 있다면 이를 이용해 변환
2. PropertyEditor를 이용할 수 있다면 이를 이용해 변환
3. requiredType 인자가 null이 아니라면 직접 타입 비교를 해서 변환

# 설정
ConversionService를 등록하는 방법은 크게 웹에서 필요할 때 등록하는 방식과 일반 빈 변환 시에 등록하는 방식으로 나눌 수 있겠습니다.

웹 같은 경우에는 WebBindingInitializer(실제로는 DataBinder에 등록 됨)를 통해 등록하면 되는데 역시나 등록하는 방식은 여러가지 입니다.
<mvc:annotation-driven>을 통해서 바로 등록하거나 또는 ConversionService 구현 클래스를 빈으로 등록하고 <mvc:annotation-driven conversionService="" />를 통해 지정해줄 수도 있습니다. 또는 WebBindingInitializer를 통해서 직접 등록해줄 수도 있고, 이 때 사용할 수 있는 기본 구현 클래스로 ConfigurableWebBindingInitializer을 사용할 수도 있습니다.

팩토리 같은 경우에는 "conversionServcie"라는 빈 이름으로 등록하거나 ConversionService 타입의 빈이 등록되어 있다면 팩토리 내부적으로 룩업하여 등록해주게 됩니다. 실제 룩업하는 지점은 AbstractApplicationContext.finishBeanFactoryInitialization()이 되겠습니다.

# 확장
ConversionService를 직접 구현하는 경우도 있을 수 있겠지만 그 보다는 일반적으로 Converter 인터페이스를 구현하게 될 것 입니다. from 타입과 to 타입에 맞게 메서드를 구현하면 됩니다. 또는 조금 더 일반화한(generic) GenericConverter를 구현할 수도 있겠습니다. 여기서는 from과 to 정보를 TypeDescirptor로 받게 되니 내부적으로 이 메타 정보를 활용해 다양한 타입 매핑을 수행할 수 있겠습니다.

ConversionService의 기본적인 구현체로는 GenericConversionService와 ConversionServiceFactory가 제공되며, ConversionServiceFactory.addDefaultConverters(..) 메서드를 보시면 기본적으로 제공되는 다양한 Converter를 확인하실 수 있습니다.
저작자 표시 비영리
크리에이티브 커먼즈 라이선스
Creative Commons License
Trackback 0 Comment 0
2010/05/11 15:17

BeanPostProcessor 구현 시 주의할 점

Aware 스타일로 빈 의존성 주입을 자동화 하는 데 BeanPostProcessor을 자주 사용하곤 합니다. 스프링 내부적으로 중요하게 사용되고 있는 인터페이스죠.

다만 한 가지 구현 시 주의해야할 점이 있습니다. 저(물론, 제가 맡고 있기는 하지만 그 전에 다른 분이 개발한...)는 이 주의 사항을 인식하지 못하고 있다가 전체 서비스 레이어에 트랜잭션 프록시가 적용되지 않는 불상사(?)를 겪기도 했습니다. 그 때는 급하여 BeanFactoryAware를 통해서 해결하도록 변경하고 말았는데, 이번에 다시 찾아보니 의외로 레퍼런스에 명확하게 언급하고 있었습니다. 자세히 읽지 못한 제가 잘못이네요..

스프링 3.x 기준 레퍼런스 "3.8.1 Customizing beans using the BeanPostProcessor Interface"을 보시면 다음과 같은 문구가 나옵니다.

# BeanPostProcessors and AOP auto-proxying
Classes that implement the BeanPostProcessor interface are special, and so they are treated differently by the container. All BeanPostProcessors and their directly referenced beans are instantiated on startup, as part of the special startup phase of the ApplicationContext. Next, all those BeanPostProcessors are registered in a sorted fashion - and applied to all further beans. Because AOP auto-proxying is implemented as a BeanPostProcessor itself, no BeanPostProcessors or directly referenced beans are eligible for auto-proxying, and thus do not have aspects woven into them.

For any such bean, you should see an info log message: “Bean foo is not eligible for getting processed by all BeanPostProcessor interfaces (for example: not eligible for auto-proxying)”.

물론, 일반적인 BPP 구현 방식대로 BPP를 별도의 클래스로 구성하면 별다른 문제가 없을 겁니다. 제가 문제를 겪은 상황은 상위 공통 클래스에서 BPP를 구현해서 의존성을 찾는 방식이었습니다. 구현 방향이 조금 맞지 않았던 것이죠. 

아무튼 구현 시 주의하셔야 합니다!
저작자 표시 비영리
크리에이티브 커먼즈 라이선스
Creative Commons License
Trackback 0 Comment 0
2010/03/22 08:00

Bean Validator 확장 방법

스프링 3.0에서는 "Bean Validation(이하 BV로 줄이겠습니다)"(JSR-303)을 @MVC와 연계하여 사용할 수 있도록 Hibernate Validator를 기반으로 하는 팩터리를 구현해 제공합니다. 물론, MVC 외의 모듈에서 Validator API를 통해 이용할 수도 있습니다.

BV의 명세를 잠깐 살펴봤는데 확장 방법이 어렵지 않고, 단순한 검증 뿐만 아니라 데이터베이스와 연계한다던지 부가 정보를 내린다던지 등 다양하게 구성할 수가 있을 것 같습니다. 자세한 내용은 조금 더 살펴보기로 하고 오늘은 강의 자료 겸 간단히 테스트 해본 확장 방법만 남겨두도록 하겠습니다.

검증을 확장하고 싶을 때작성해야 할 클래스는 간단히 두 가지 입니다.

첫 번째는 검증 대상을 지정할 때 사용할 애노테이션.
두 번째는 실제 검증 로직을 수행할 검증기(Validator).

제가 간단히 시험해본 검증 시나리오는 '특정 필드의 값이 데이터베이스에 이미 존재하는지 확인'하는 내용입니다.

먼저 이 시나리오에 적합한 이름을 선정해 애노테이션을 작성합니다.
@Documented
@Target( { ElementType.FIELD })
@Retention(RetentionPolicy.RUNTIME)
@Constraint(validatedBy = MenuNameConflictValidator.class)
public @interface Unique {
String message() default "메뉴 명이 중복되었습니다";
Class<?>[] groups() default {};
Class<? extends Payload>[] payload() default {};
}

@Constraint 애노테이션을 통해 실제 검증을 수행하는 검증기를 지정해주면 됩니다.
주의해야 할 점은 반드시 groups()와 payload()를 추가해야 합니다. 그렇지 않으면 왜 작동하는지 쉽게 알 수 없는 예외를 받게 됩니다.(그래서 처음에 조금 해맸습니다..)

그 다음으로는 검증기를 작성합니다.
public class MenuNameConflictValidator implements ConstraintValidator<Unique, String> {
@Autowired
private MenuDao dao;

@Override
public void initialize(Unique mark) {
}

@Override
public boolean isValid(String menuName, ConstraintValidatorContext context) {
if (dao.existMenuName(menuName) != 0) {
return false;
}
return true;
}
}

Menu라는 객체의 'menuName' 프로퍼티의 값을 중복 체크하는 로직입니다. isValid()에서 검증 로직 구현 후 통과 여부를 true/false로 지정하면 됩니다. 검증기 자체가 빈으로 등록되니 기존 서비스를 충분히 재활용할 수 있습니다. (다양한 표준/기술/기법과의 통합을 중요시 하는 스프링의 전략을 놀라울 따릅입니다..)

확장이 끝났습니다. 그럼 실제로 사용을 해봐야겠죠..
public class Menu implements Serializable {
@Unique
@NotNull
@Pattern(regexp = "[\uAC00-\uD7A3, a-z, A-Z, 0-9]+", message = "메뉴 이름에 영문,한글,숫자만 가능합니다!")
private String menuName;
}

menuName 프로퍼티는 기존의 유효성 검증 로직과 함께 확장한 @Unique 애노테이션을 통함 검증까지 함께 거치게 됩니다. 

이상입니다.
저작자 표시 비영리
크리에이티브 커먼즈 라이선스
Creative Commons License
Trackback 0 Comment 0
2010/02/22 21:00

스프링 3.0 체인지 로그 분석 - Spring 3.0 RC2 ~ GA

스프링 3.0 체인지 로그 분석을 3.0.0 GA까지 마무리 했습니다.
훑어보기는 몇 주전에 다해놓고 이제야 스프링 노트에 옮겨두었네요..

얼마전에 3.0.1이 출시되는 바람에 바로 3.0.1도 훑어봐야 겠습니다.

저 같은 경우에는 3.0 도입의 주 목적이 향후 JavaEE 스펙에 대응성을 높이고자 였습니다. 
그 외에 신기능들은 +@로 얻는 부수입정도^^.

혹시나 3.0.0을 검토하시는 분이 계시다면 참고하세요.
시간이 조금 지나고 나면 언제 한 번 3.0.0 도입에 따른 변화에 대해 썰을 풀 수 있을 것 같습니다.
그럼 그 날이 오기를 기다리며 이만 줄이겠습니다.

저작자 표시 비영리
크리에이티브 커먼즈 라이선스
Creative Commons License
Trackback 0 Comment 0
2010/02/03 08:49

테스트 컨텍스트 프레임웍의 스테레오 타입 종류와 범위

겸사겸사 Spring의 TestContext 프레임웍을 살펴보고 있습니다. 일단 제가 좀 정리를 하고, 현재 개발하고 있는 프레임웍의 기존 800여개의 테스트 코드를 마이그레이션 할 생각입니다.

우선 클래스 상속 구조의 메소드 재정의를 통해서 구현하는 방식이었던 기존 스프링 테스트 지원 기능은
테스트 컨텍스트 프레임웍으로 넘어오면서 완전히 애노테이션을 기반으로 하는 이벤트 방식으로 변경되었습니다.

내용을 파악하는 첫 번째 방법 중의 하나가 가장 밀접하게 사용되는 스테레오타입(애노테이션)을 파악하는 일입니다.
나아가 이 애노테이션의 호출 흐름과 범위를 인식하는게 중요합니다.


그래서 간단히 정리해봤습니다.
애노테이션이 호출되는 순서대로 나열했고, 바운더리는 Test Class 수준, Test Instance 수준, Transaction 수준으로 나누었습니다.
특히나 데이터베이스와 연동하여 테스트를 할 시에는 Transaction 관련 스테레오타입의 앞 뒤를 명확히 이해하는 것이 중요합니다.


저작자 표시 비영리
크리에이티브 커먼즈 라이선스
Creative Commons License
Trackback 0 Comment 0
2010/01/19 22:24

스프링 3.0 체인지 로그 분석 - Spring 3.0 RC1



드디어 RC 버전입니다. RC 1에서는 3.0 마일스톤 버전에서 추가된 다양한 기능과 기술에 대한 보완 작업이 주를 이뤘습니다.
또한 JEE 6 (JSR-330, JSR-303, JSF2)에 추가된 표준 스펙에 대한 지원 기능도 추가되었습니다.

그 외에 테스트 쪽에서는 JUnit 버전 별 호환성과 @Rule 지원이 추가 된 것이 눈에 띄고, 일부 핵심 라이브러리(CGLIB, AspectJ, JUnit)가 갱신되었습니다.

한 가지 사소하지만 관심이 가는 변경은 '배열 형식의 'MultipartFile 매핑 지원' 입니다. 기존에 몇 번 포럼이나 블로그에 이슈가 됐던 문제로, 이제 공식적으로 멀티 파트 파일을 배열로 받을 수 있게 지원하게 됐습니다. 그런데 이러다 보니 내부 구현 방식이 변경되어 멀티파트 리졸버의 코드가 변경되버리게 됐습니다. java.util.Map을 받던 생성자가 org.springframework.util.MultiValueMap으로 교체되었습니다. (덕분에 프레임웍 코드를 고치게 되버렸습니다;)
저작자 표시 비영리
크리에이티브 커먼즈 라이선스
Creative Commons License
Trackback 0 Comment 0
2010/01/11 12:30

스프링 3.0 체인지 로그 분석 - Spring 3.0 M4



앞 세 개의 마일스톤 버전에서는 굵직하게 새로운 기능들이 추가된 반면에 M4에서는 코어부터 테스트까지 여러 부분에 있어서 균형을 맞추고 보완하는데 촛점을 맞춘 듯 합니다. 이슈도 170개로 앞 세 개의 마일스톤보다 많은 이슈를 처리했고, 그 중 대부분이 기능 추가보다는 버그 픽스와 개선 이슈를 처리했습니다.
마일스톤 마지막 버전이라 그런가요?

이번에는 눈에 띄는 변경 내역을 찾기가 어렵지만 굳이 찾아 보자면,
새로운 기능 추가보다는 소소하지만 그 동안 당연히 될 것이라 생각했지만 왜 지원을 안 할까 하는 두 가지의 내용을 들 수 있을 것 같습니다

1. XML import 요소에서 상대 경로(*) 지원
이제 <import resource="mySpringFolder/*-cfg.xml"/> 해도 됩니다.

2. NamedParameterJdbcTemplate.batchUpdate()의 네임드 파라미터 기반 배치 연산 지원
SimpleJdbcTemplate에서는 네임드 파라미터를 지원하는데 유독 NamedParameterJdbcTemplate에서만 지원하지 않았습니다. 왜 SimpleJdbcTemplate에서만 되냐 살펴 봤더니 foreach 문을 쓰는 코드를 제외하고는 NamedParameterJdbcTemplate에 적용하기가 전혀 문제가 없습니다. 그래서 저는 SimpleJdbcTemplate에 있는 코드를 포팅해와서 쓰고 있었는데요(JDK 1.4 호환성 보장이 필수라서 말이죠..), 이제야 지원이 되네요.


저작자 표시 비영리
크리에이티브 커먼즈 라이선스
Creative Commons License
Trackback 0 Comment 0