2013년 2월 16일 토요일

Spring MVC Controller 선후처리기 만들기

ASP.NET 웹 어플리케이션은 어플리케이션 Lifecycle, Page의 Lifecycle 에 상세한 event 를 정의하고 있어, event handler를 정의하면, 여러가지 선처리나 후처리를 수행할 수 있습니다.

Spring MVC 에서는 어떻게 하나 봤더니 Controller 에 Interceptor 를 등록하면 되더군요.

단계를 요약하자면...

  1. org.springframework.web.servlet.HandlerInterceptor 또는 org.springframework.web.servlet.handler.HandlerInterceptorAdapter 를 상속받아 preHandler, postHandler, afterComletion 등에 원하는 작업을 구현합니다.
  2. servlet.xml 에 위에서 작성한 Interceptor 를 등록합니다.

아주 쉽죠?

그럼 실제 예제와 함께 보시죠. 예제는 Spring Framework 3.2.1.RELEASE 와 Hibernate 4.1.9 Final 로 제작했습니다.

UnitOfWorkInterceptor 는 사용자 요청이 있으면 Start 하고, 요청 작업이 완료되면 Close 하도록 합니다. 이는 Hibernate 를 이용하여 Unit Of Work 패턴을 구현하여, 하나의 요청 중에 모든 작업을 하나의 Transaction으로 묶을 수 있고, 웹 개발자에게는 Unit Of Work 자체를 사용하기만 하면 되고, 실제 Lifecycle 은 Spring MVC 에서 관리하도록 하기 위해서입니다.


보시다 시피, preHandle 에서는 Controller의 메소드가 호출되기 전에 (즉 Unit Of Work 를 사용하기 전에) UnitOfWorks.start() 를 호출하여, hibernate의 session을 열어, Hibernate session 작업을 할 수 있도록 미리 준비해줍니다.

postHandle 에서는 아무 작업도 하지 않는데, 실제 View 에서 ViewModel 를 binding 할 시에, lazy initialized 되는 associated entity를 후에 가져 올 수 있기 때문입니다. 여기서 unit of work 를 끝내버리면, session을 닫아버려, lazy initialize 작업에서 예외가 발생하게 됩니다.

afterCompletetion 에서는  View 작업까지 완료되고, Client 에 Reponse 를 보내기 바로 직전에 호출됩니다. 여기서 unit of work 를 close 합니다.

다음으로는 웹 어플리케이션에 Spring MVC Context 를 설정 시 interceptor를 등록하기만 하면 됩니다.


위와 같이 bean 등록 시에 interceptor를 등록해 주시면 됩니다^^
Spring AOP 를 사용해도 되지만, 요 방법이 가장 간단하고, 쉽게 이해할 수 있을 것 같습니다.

다른 블로거의 글에는 logging 으로 예제를 많이 많들었더군요...
asp.net 으로는 제가 간단하게 성능 측정하는 코드를 예제로 만들어보긴 했지만, 쓸모는 없지요^^
위의 unit of work관련 코드는 asp.net 으로 구현한 것은 상용 제품의 코드로 쓰이고, 아직도 많은 회사에서 구동되고 있습니다...
이를 spring mvc, hibernate 로 포팅한 작업입니다.

2013년 1월 29일 화요일

Scala - 컬렉션을 병렬로 실행하고 정렬된 결과를 얻기

Scala 의 좋은 점이 기본적으로 병렬 처리를 수행할 수 있도록 병렬 형태의 컬렉션 자료구조를 지원하고, 일반 컬렉션도 .par 를 이용하여, 병렬 처리를 지원하는 자료구조로 변환할 수 있습니다.

다만 아쉬운 점이라고 한다면, 병렬 처리 자체가 정렬을 지원하지 않기 때문에, 정렬된 순서대로 결과가 나오지 않는다는 단점이 있습니다.

.NET에는 .asParallel() 외에 .asOrdered() 가 있어, 병렬 처리를 하면서 정렬된 결과를 얻을 수 있습니다.

Scala에서는 아쉽게 지원되지 않으므로, 한 번 더 처리 해 줘야 합니다.
다음과 같이 처리해야 할 정보를 받아 mapper 함수를 이용하여 작업을 처리한다고 한다면, 단순히 map(mapper(_) 만 수행하면 되겠지만, 정렬을 수행하기 위해, 입력 변수도 같이 저장하여, 정렬을 수행할 수 있도록 한 후, 정렬 후에 Tuple에서 원하는 결과만 빼서 전달하는 것입니다.


뭐 입력 자체가 정렬이 안된 경우도 있을 수 있고, 입력값 자체가 map 형태라면 좀 달라져야 하지만, 유사한 로직으로 해결이 가능할 것입니다.
Java로도 유사한 코드를 만들 수 있지만, Scala 가 더 편하네요^^

2013년 1월 23일 수요일

[강추] Google Guava 자료

Google Guava 를 더 파보니, .NET TPL 의 Task Chain 기능도 있네요. ㅋ
MoreExecutors  도 있고 흠...

Guava Wiki 보는 것도 좋지만, 실제 예제 소스가 아주 풍부하게 많은 자료가 있어 소개합니다.

후~ 저도 많이 안다고 생각했는데, 유용한 걸 더 찾을 수 있었네요^^ 역시 아는 만큼 보이나봅니다.