서블릿 3.0 메이븐 의존성은?

2.5까지는 groupId가 javax.servlet이고 artifactId가 servlet-api이고 version은 2.4나 2.5썼었으니까 3.0도 버전만 3.0으로 바꾸면 되겠지라고 생각했지만 안 그랬다.

그래서 좀 찾아봤는데 이게 답인것 같다.

http://stackoverflow.com/questions/1979957/maven-dependency-for-servlet-3-0-api

여길보면 조금 엉뚱한게 답변으로 채택되어있는데 굳이 써드파티 메이븐 저장소에서 끌어오도록 하느니.. 되도록이면 중앙 저장소에서 가져오는게 더 깔끔하고 신뢰가간다. 그래서 난 앞으로 저렇게 쓸 계획이다.

[Servlet 3.0 Asynchronous Support] 비동기 서블릿

쉽지 않다. 일단 배경 자체가 매우 긴데…

http://www.javaworld.com/javaworld/jw-02-2009/jw-02-servlet3.html

이 글에서 배경을 잘 설명하고 있다.

HTTP 1.0과 HTTP 1.1의 차이점부터 시작해서, Thread per connection을 설명하고, page-by-page 방식에서 커넥션 쓰레드가 지연상태로 있기 마련인지라, JDK 1.4에 추가된 NIO를 사용해서 놀아도 되는 커넥션 쓰레드를 회수하여 새로운 요청을 처리할 용도로 사용하도록 되었다고 한다. 그러다, Ajax의 등장으로 page 당 요청수가 급증하게되고, 그 중에서도 느리고 제한적인 자원에 접근하는 요청일 경우에는 처리용 쓰레드가 대기하는 상황이 자주 발생하게 됐다. 그래서 등장한 것이 바로 Servlet 3.0의 비동기 기능이다. 대기해야 하는 리소스를 요청한 상태에서 처리용 쓰레드를 계속 대기 상태로 유지(동기)하는게 아니라, 처리용 쓰레드는 대기해야 하는 리소스를 요청하고 회수했다가, 리소스가 다시 가용해졌을 때 처리를 이어가게 해주는 것이다. 이렇게되면, 가만히 기다리느라 멍때리고 있던 리소스를 다른 작업 처리하는데 사용할 수 있으니 훨씬 효율적이라서, 잘하면 처리량이 올라갈 수도 있겠다.

결국 DB로 쏠릴것이다. 지금도 성능의 대부분은 DB에서 먹히는 거라고 하지만, 그걸 뭘 어째겠는가. 그 앞에 캐시를 둬서 잘 운영하거나, DB 자체를 좀 더 효율적으로 활용하는 방법을 찾거나, 그건 또 다른 문제니까 논외로 패스.

어쨌거나, 지금까지 배경을 살펴보면 대충 이런것 같다.

  • 일단 두 종류의 자원이 있다. 하나는 커넥션용. 하나는 처리용.
  • 커넥션용 자원은 이미 여러 서블릿 컨테이너가 NIO를 사용해서 효율적으로 작업해 뒀기 때문에 개발자가 신경쓰지 않아도 됨. – “Today, popular Web servers — including Tomcat, Jetty, GlassFish (Grizzly), WebLogic, and WebSphere — all use thread per request through Java NIO.”
  • 처리용 쓰레드는 DB 요청이나, 웹 서비스 요청을 했을 때 대기하게 되는데, 이건 서블릿 3.0의 비동기 기능을 활용해서 절약할 방법이 생김. (어느정도 효과가 있을지는 모르겠음.)

하지만, 이 글에서 보여주는 예제는 ServletContextListener와 조합하고 있는데, 그리 깔끔해 보이는 예제는 아니었다.

http://blogs.oracle.com/enterprisetechtips/entry/asynchronous_support_in_servlet_3

다음으로 읽은 글인데, 비교적 깔끔한 예제와 설명을 제공한다. 그런데 저기 있는 예제 코드처럼 요청이 올때마다 new ThreadPoolExecutor(10)를 생성하는 건 매우 위험해보이고, 쓰레드 풀을 스프링에 빈으로 등록해두고 쓰는게 좋겠다. 스프링 @Async 기능 관련해서 무슨 클래스 이름이 있었는데 잊어버렸다. @_@; 머더라.. 뭔 Factory였는데.. 또 패스.

그치만 저 글로는 AsyncContext, AsyncListener의 주요 기능을 파악하기는 어려웠다. API를 읽어본다고 크게 도움이 되지도 않고, 언제 이 메서드를 사용해야 하는 것인지 알아야 할텐데..

http://jcp.org/en/jsr/detail?id=315

그래서 스펙을 열어봤다. 스펙 문서는 서블릿의 모든것이 설명되어 있는 필독 문서인데, 난 아직 전부다 읽어본적은 없다. 이번 기회에 한번 다 읽어볼까 싶기도 하고… 어쨋든 이 문서에서 비동기 관련 내용이 잘 설명되어 있다. 2.3.3.3을 보면 된다. 사실 나도 아직 다 읽은건 아니라서.. @_@ 일단 링크 정리하면서 요약하려고 적기 시작한거라. 나중에 레퍼런스를 요약해서 정리해야겠다. 서블릿 3.0 부셔버리겠어!!

http://weblogs.java.net/blog/mode/servlet3.0/servlet3.0-javaone09.pdf

마지막으로 전체적으로 훑어보기 좋은 PDF 문서가 있다. 여기 그림과 코드가 주옥같다. 발표 영상도 구할 수 있으면 좋겠지만, 귀찮아서 찾아보진 않았다.

예제를 하나 만들어 보고 슬슬 자야겠다. 벌써 12시 30분을 향해가는구나. 간단한 웹 서비스 요청을 한다고 가정해보자. 야후 주식 API를 호출해서 여러 주가 정보를 받아와야 한다고 가정해보자.

여기서 사용한 야후 주시 정보는 스프링 RestTemplate응 이용했다.

이렇게 짜봤는데… 흠.. 뭔가 좀… 응답이 한방에 오는게 어째 좀 찝찝하다. 응답이 조각 조각 와야 하는거 아닌가. 크롬 인스펙터로 보면 응답 Transper-Encoding: chuncked 이긴한데.. 내가 원한건, Start가 먼저 응답으로 오고, 그 다음에 주식 정보가 다시 응답 조각으로 와서 완료되는 것인데.. 흠.. 디스패치를 이용해야되나.. 아. 찝찝한데 시간은 벌써 1시 반이 넘었고… 자야겠다. 젠장.. OTL…

서블릿 레퍼런스랑 자바 컨커런시 프로그래밍 좀 잘 봐야겠다.

출근길에 Dispatch를 사용하도록 코드를 변경해봤다.

이번에도 내가 원하는대로 되진 않았다. 일단 브라우저에는 Start만 보내고, 그 다음 리모트 호출이 완료된 다음 주가 정보를 출력하는 것이 내가 원하는 결과였는데.. 흠.. 화면단에서 자바스크립트로 코딩이 들어가야 하는걸까? 화면단 코딩을 하지 않더라도, 적어도 크롭 인스펙터에 두줄로 나와야 하는거 아닐까나.. 흠;; 모르겠군;

[Servlet 3.0 @MultipartConfig]파일 업로드가 좀 편해졌으려나…

먼저, Servlet 3.0으로 파일업로드를 해보자.

일단, 간단한 파일 업로드 폼을 만들었다.

다음은 @WebServlet@MultipartConfig를 추가해서 업로드 파일을 저장할 장소와 파일 크기, 요청의 총 크기 등을 설정할 수 있다.

여기서 핵심은, Part라는 API다. MultiPart 타입의 요청에서 한 부분을 Part라고 참조할 수 있으니, 해당 요청에 파일만 업로드 했다는 가정하에, 한 파일당 하나의 Part가 생신다고고 볼 수 있겠다. 이 Part에 접근하는 방법은 두개.

  • 전체다 가져오기: req.getParts()
  • 한개만 가져오기: req.getPart(String name)

일단 괜찮아 보인다. 용량 설정과 디렉토리 설정을 할 수 있다는 것이 좋다. 이렇게 하면, 요청마다 업로드와 관련 된 설정을 유동적으로 가져가기 좋아보인다. 대신 여러번 설정해야 하면 귀찮기도 하겠지만, 커스텀 애노테이션을 만들거나, 자바 클래스 상속으로 해결할 수 있을지도 모르니깐.. (근데 이건 안해봐서 좀.. ㅋ)

시험삼아 chmox.dmg파일을 업로드해보고, Request 정보를 출력해봤다.

Name:
file
Header:
content-type
application/octet-stream
content-disposition
form-data; name=”file”; filename=”Chmox-0.3.dmg”
Size:
256905

파일 이름을 알아내려면 content-diposition 헤더 정보를 읽어서 그 중에서도 filename=”부터 “까지를 잘라내야하는데, 참 귀찮은 일이다. 그보다는 파일을 선택했을 때 뷰에서 해당 파일 이름을 input type=”text”에 자동으로 채워주고, 서버에서는 그 값을 받아서 사용하는게 더 좋겠다.

이번에는 이 기능을 스프링 3.1을 사용해서 해봤다.

http://static.springsource.org/spring/docs/3.1.x/spring-framework-reference/html/mvc.html#mvc-multipart-resolver-standard

레퍼런스를 참고했다. 일단 레퍼런스에 글로만 설명된대로 web.xml을 손봐야한다.

이렇게 하면 이제 해당 DispatcherServlet으로 들어오는 요청이 Servlet 3.0 파일 업로드 기능을 사용할 수 있게 된다.

아 그리고 빈을 하나 추가해줘야 한다. 아파치 커먼스 파일업로드를 쓸때도 하나 등록했었으니깐.. 이건 뭐 쌤쌤.

이전에는 요거 대신 아래 녀석을 등록했었다.

차이가 있다면, 파일 업로드 용량을 스프링 빈으로 설정하던걸, web.xml로 옮겨갔다는 것… 난 이전이 더 편한것 같다.

이런 고민이 생긴다.

“특정 요청마다 다른 기준으로 용량을 제한해야 한다면?”

스프링으로는 어떻게 하면 좋을까? multipartResolver는 DispatcherServlet당 하나밖에 못쓰니까.. 뭔가 URL 별로, 다른 MultipartResolver를 사용할 수 있는 기능을 가진 MultipartResolver를 만들면 될까나~?

[Servlet 3.0 @WebServlet]스프링 DispatcherServlet을 서블릿 3.0 @WebServlet으로 올려볼까?

서블릿 3.0에 web.xml없이 애노테이션만 추가하면 서블릿으로 자동 등록되는 기능이 생겼다.

http://www.servletworld.com/servlet-tutorials/servlet3/webservlet-annotation-example.html

자세한 내용은 여기 있고..

우선, pom.xml에 의존성을 추가해야한다.

이렇게 두개가 필요하고, 이런류의 의존성은 보통 provided 스코프로 사용하게 좋은 습관이다. 왜그런지는 생략;

이렇게 간단하게 자바 코드만 추가하고, web.xml을 전혀 만들지 않아도, 브라우저에서 /test를 요청하면 Hello를 볼 수 있다.

난 사실 처음에 스프링 3.1에서 서블릿 3.0을 지원한다길래 이런 모습을 상상했었다.

서블릿 3.0부터는 web.xml을 사용할 필요가 없고, DisaptcherServlet도 HttpServlet을 (매우 깊게) 상속해서 만든 클래스니까 이런식으로 등록할 수 있지 않을까? 싶었다.

해보니까 잘 된다.

그래도 저렇게 쓰진 않겠지;;; ㅋ