Servlet 2.1 부터 HttpSession 의 getSessionContext() 메소드가 Deprecate 되었다.
저렇게 가져온 HttpSessionContext 에서 getSession(id) 해버리면 끝났던 것이, 이제는 직접 Map 을 만들던가 하여
getSession(id) 를 구현해 주어야 하는 불편함이 생겼다.
아래 코드 처럼, HttpSessionListener 를 implement 하여 Session 이 생성되거나 사라질 때 마다 Map 에 넣어서 관리를 해주도록 코딩을 해야 한다. 나중에 현재 접속중인 사용자와 같은 기능을 할때에도 아래를 응용하여 잘 쓰면 된다.
17 public class SessionListener implements HttpSessionListener{
18
19 public void init(ServletConfig config){
20 }
21
22 /**
23 * Adds sessions to the context scoped HashMap when they begin.
24 */
25 public void sessionCreated(HttpSessionEvent event){
26 HttpSession session = event.getSession();
27 ServletContext context = session.getServletContext();
28 Map activeUsers = (Map)context.getAttribute("activeUsers");
29
30 activeUsers.put(session.getId(), session);
31 }
32
33 /**
34 * Removes sessions from the context scoped HashMap when they expire
35 * or are invalidated.
36 */
37 public void sessionDestroyed(HttpSessionEvent event){
38 HttpSession session = event.getSession();
39 ServletContext context = session.getServletContext();
40 Map activeUsers = (Map)context.getAttribute("activeUsers");
41
42 activeUsers.remove(session.getId());
43 }
44 }
직접 Java 코드에서 request.getSession(true); 했을 때, Listener 가 잘 Call 되지 않는다라는 글도 있었는데, 이점을 잘 테스트 하며 사용해보도록 한다.
그리고, Clustered 환경에서 혹시나 문제 소지가 있을 수도 있으니, 테스트 해가면서 사용한다.
--------------------------------------------------------------
request.getRequestedSessionId()는 지금 만들어진 세션Id을 보기 위함이 아니라,
이전에 만들어진세션의 Id를 보기 위함입니다
--------------------------------------------------------------
세션은 보통 세션만 쓰지는 않습니다. 요것이 life타임이 얻는것이나 셋팅하는 값으로 잘 안되기 때문입니다.
디폴트가 30분인데 30분이 되기 전에 사라지는 일이 종종발생하기 때문입니다.
세션에 대한 메소드를 추가 해서 소스를 올렸습니다.
getCreateTime : 생성된 시간을 반환해주는 메소드입니다.
getLastAccessedTime : 마지막으로 세션을 access한 시간을 반환해줍니다.
getMaxInactiveInterval : 마지막 acceess로 부터 살아남을 수 있는 시간입니다.
하지만 전 그전에 사라지는 경우를 종종 봐왔기때문에 오히려 살아남을 수 있는 최대한의 시간이라고 말하고 싶습니다.
getId : 서버가 클라이언트별루 주는 세션ID입니다. 인식자인 셈이죠..
아래 소스를 실행하면 아이디를 넣어 달라는 말이 나올겁니다. 거기서 아이디를 넣으면 그 아이디를 세션에 넣습니다.
그리고는 소스 하단부분의 if문장을 실행하게 되죠.
--------------------------------------------------------------
일정한 시간이 지나서, 이미 해당 HttpSession 이 invalidate 되었군요...
이미 invalidate 된 session을 다시 invalidate 시키려고 하면 IllegalStateException이
발생합니다. 이 경우에 발생하는 IllegalStateException은 무시하시면 되겠습니다.
// 위의 컨텍스트를 이용해서...
Enumeration ids = context.getIds();
// 최신의 상태가 아닌 세션을 검색하기위해 세션ID를 살펴봄..
while (ids.hasMoreElements()) {
String id = (String)ids.nextElement();
out.println("Checking " + id + "...."); // 세션의 ID가 나오겠죠...
HttpSession session = context.getSession(id);
. . .
String foreignUser = (String)foreignSession.getValue("user_id");
}
--------------------------------------------------------------
1. jsp에서 회원로그인에서 session을 받아 처리하는 부분하고 이 session을 가지고
정보수정이랑 하고 싶은데 어떻게 처리를 해 줘야 하나요?
로그인할때 회원아이디값을 넘겨줍니다.
값을 받은 페이지에서는 그 값을 세션에 넣습니다.
이렇게요..
session.putValue("id",userid);
여기서 userid는 회원아이디값을 받은 String입니다.
그러면 세션에 id가 들어가겠지요.
다음으로 정보수정하는 페이지에 세션을 가져오는 문장을 넣지요.
session.getValue("id");
그리고 그 값을 String형으로 변환해서 임의의 변수에 넣습니다.
그리고 그 임의의 변수를 이용해서 해당회원의 정보를 수정하면 되겠지요...
--------------------------------------------------------------
1. >client별 세션객체를 얻어서 client들의 세션 저장내용을 지우는 부분입니다...
>근데 맨날도 아니구 가끔 아주 가끔 foreignSession객체에서 NullPointerException이
>발생하는데요... 왜 그런에러가 나는지 모르겠네요...
일종의..동기화 문제로 보여집니다.
세션목록을 가져온 후,
그리고 세션저장내용을 지우기 전에
세션타임아웃 등의 이유로 세션이 없어지면
해당 id값이 없으니 null이 들어갈것이구..
모 일단 그렇게 보여지네요 ^^
또한 참고하세요..
☞ 로그인하고 로그아웃할때 데이터베이스 테이블에 값을 설정해서 비교하는 방법이 있습니다.
☞ 세션정보에 로그인한 사용자의 데이터도 넣을수 있을수 있다면,
세션을 체크해서 주기적으로 데이터베이스를 체크한다면 가능할거 같기두 한데요...
☞ javax.servlet.http.* 패키지에 보면 HttpSessionBindingListener 인터페이스가 있습니다.
이 인터페이스에는 몇개의 메소드가 있는데 그 중 한개가 아래에 있는것입니다.
// HttpSessionBindingListener 구현
public void valueUnbound(HttpSessionBindingEvent http) {
logout();
}
위 메소드는 서블릿에서 사용자의 세션이 끊어졌을때 생기는 이벤트입니다.
그러니깐 사용자가 로그인 했을때 데이타 베이스에 세션 정보가 있다면 중복 로그인한 사용자이고, 없다면 세션 정보를 넣어두고, 위 메소드에서 세션 종료시 DB에 저장된 세션정보를 지우던지 필드를 V팅하던지 작업을 하시면 될것같습니다.
? 관련 메소드 정리
Object getAttribute(String name)
- 주어진 이름으로 세션에 저장된 객체를 리턴한다. ※ Object getValue(String name)
Enumeration getAttributeNames()
- 세션에 저장된 모든 객체들의 이름을 Enumeration 타입으로 리턴한다. ※ String
getValueNames()
long getCreationTime()
- 1970년 1월 1일 0시 0분 0초를 기준으로 세션이 생성된 시간을 리턴한다.(단위 ms)
String getId()
- 세션의 ID를 리턴한다.
long getLastAccessedTime()
- 1970년 1월 1일 0시 0분 0초를 기준으로 클라이언트가 이 세션에서 요청을 보낸 마지막 시간을 리턴한다.
int getMaxInactiveInterval()
- 서버가 클라이언트의 요청없이 세션을 유지하는 최대 시간을 리턴한다. (단위 초)
1. Class 가 이미 로드되어있는지 체크
2. Parent 의 Class Loader 에게 Class Load 하도록 위임함
3. 2 과정을 반복하며 최상위 Class Loader 까지 간다
4. 더이상 부모 ClassLoader 가 없으면, BootStrapClassLoader() 에게 요청한다
5. BootStrap 부터 다시 차근히 내려오면서 Class 로딩을 한다.
6. 클래스가 로드 되면 해당 클래스를 리턴한다
7. 이상이 ClassLoader.loadClass() 메커니즘이고, 만약 parent 에서 못찾으면,
자신의 findClass() method 를 call 해서 클래스를 찾는다
Custom ClassLoader 를 생성할 때, 생성자에 parent classloader 를 지정할 수 있게 되어있음
만약 지정하지 않으면, 기본적으로 getSystemClassLoader() 를 통해, SystemClassLoader 를
parent 로 지정함. 이 system class loader 는 현재 invoking thread 의 context class loader 로 설정된다
* BootStrap 클래스로더 : Java Runtime Library 에 있는 클래스를 로딩하는 역할을 맡고 있음. 클래스로더 체인의
가장 첫번째임. 기본적으로 rt.jar 에 있는 클래스를 Bootstrap ClassLoader 가 로드 한다.
* 하나의 JVM 에 여러 클래스로더가 각각 같은 Package.Class 를 Load 하면, 각각의 인스턴스가 따로 생긴다.
결국, Java 에서의 클래스 생성은 "패키지, 클래스, 클래스로더" 의 3가지의 조합으로 구분되는 것이다
* Java2 의 표준 Runtime Library (jre/lib/rt.jar) 는 공개/내부사용 클래스 로더들이 있다
- java.net.URLClassLoader
파일, HTTP, FTP 등을 사용하여 Class 를 Load 할 수 있는 ClassLoader 임
public static void main(String[] args) throws Exception {
URL[] urls = { new java.io.File("/usr/classes").toURL(); }
URLClassLoader ucl = new URLClassLoader(urls);
Class kalss = ucl.loadClass("javacan.exam.HelloWorld");
Object obj = klass.newInstance();
// obj를 사용하여 적절한 것을 한다.
}
}
- BootStrap 클래스로더
엄밀히 말해 Java 클래스로더가 아니고, 네이티브 로더로, Object 와 같은 코어 자바클래스를 VM 에 로딩할때 사용된다. sun.boot.class.path 프로퍼티에 정의 된 값을 사용하여 자바 런타임 라이브러리를 찾는다. 만약 명시적으로 지정하지 않으면 <JDK>/jre/lib/rt.jar 로 부터 런타임 클래스들을 로딩한다.
JDK 1.0 이나 1.1.X 대는 CLASSPATH 나 -classpath 에 런타임을 추가해줬어야 하지만, Java2 부터는 BootStrap 클래스로더가 런타임라이브러리를 자동으로 로드해주므로 지정 할 필요가 없다.
- sun.misc.Launcher$ExtClassLoader
자바의 확장클래스를 로드할 때 사용한다. ExtClassLoader 는 URLClassLoader 를 상속하며, java.ext.dirs 프로퍼티에 지정한 디렉토리에 위치한 .jar 들로 부터 클래스를 읽어온다. 명시하지 않으면 기본적으로 <JDK>/jre/lib/ext 디렉토리에 있는 .jar 들을 읽어서 클래스를 로드한다
- sun.misc.Launcher$AppClassLoader
시스템 또는 어플리케이션 클래스로더라고 불린다. java.class.path 프로퍼티에 명시된 경로에서 코드를 로딩하는 클래스로더이다. URLClassLoader 를 상속한다. CLASSPATH 에 있는 디렉토리나 .jar 파일들은 모두 URL 로 변환되어 AppClassLoader 에게 전달된다.
ClassLoader.getSystemClassLoader() 를 호출하면 이 클래스가 리턴된다. 개발자가 작성한 대부분의 클래스는 이 클래스로더를 통해 로드된다. AppClassLoader 는 부모 ClassLoader 로 ExtClassLoader 를 지정하고 있으므로, ext 디렉토리에 있는 jar 파일로 부터 클래스들을 로드할 수 있다.
- sun.applet.AppletClassLoader 브라우저가 Applet 의 바이트코드를 다운로드 하고, 그 애플릿을 실행하기 위한 클래스를 로드하는 Class Loader 이다. URLClassLoader 를 상속받고 있어서, HTTP 나 FTP 등을 통해 클래스를 로드 가능 한 것이다. 그러나 IE 나 각 브라우저 별로, 애플릿 클래스로더를 구현하고 있는 경우가 있어, 브라우져 별로 동작이 다를 수 있다.
- java.security.SecureClassLoader JVM 에 바이트코드를 로딩하고 사용하는데에 관한 보안을 제어하는 추상클래스로, URLClassLoader 를 포함한 ClassLoader 가 상속받아서 사용하는 추상클래스이다.
- java.rmi.server.RMIClassLoader
ClassLoader 가 아니며, RMI 런타임에서 클래스의 로딩과 마샬링을 처리해주는 래퍼클래스이다. 실제로sun.rmi.serer.LoaderHandler 와의 간단한 브릿지 역할을 하는 클래스이다. 실제 클래스 로딩은 LoaderHandler 의 Inner 클래스가 담당하게 된다. 이때 이 inner 클래스들은 URLClassLoader 를 상속받아 구현되어 있다.
* Custom ClassLoader 는 findClass(String) 를 구현하여 자신만의 클래스 로딩에만 신경쓰면 되며, 나머지는 parent 로 올리면 된다.
"http1-w2 [container1-15]" prio=10 tid=0x000000010140f2c0 nid=0x3b runnable [0xffffffff578fe000..0xffffffff578ff92
8] at jeus_jspwork._600_thead_5fmw_5fjsp._jspService(_600_thead_5fmw_5fjsp.java:65)
- waiting to lock <0xffffffff7238ca98> (a java.lang.Object)
at jeus.servlet.jsp2.runtime.HttpJspBase.service(HttpJspBase.java:106)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:818)
at jeus.servlet.jsp.JspServletWrapper.executeServlet(JspServletWrapper.java:94)
at jeus.servlet.servlets.JspServlet.execute(JspServlet.java:359)
at jeus.servlet.engine.HttpRequestProcessor.run(HttpRequestProcessor.java:265)
"http1-w0 [container1-13]" prio=10 tid=0x0000000101196f40 nid=0x39 waiting for monitor entry [0xffffffff57cfe000..
0xffffffff57cff828]
at jeus_jspwork._600_thead_5fmw_5fjsp._jspService(_600_thead_5fmw_5fjsp.java:65)
- waiting to lock <0xffffffff7238ca98> (a java.lang.Object)
at jeus.servlet.jsp2.runtime.HttpJspBase.service(HttpJspBase.java:106)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:818)
at jeus.servlet.jsp.JspServletWrapper.executeServlet(JspServletWrapper.java:94)
at jeus.servlet.engine.ServletWrapper.execute(ServletWrapper.java:220)
at jeus.servlet.jsp.JspServletWrapper.execute(JspServletWrapper.java:139)
at jeus.servlet.engine.HttpRequestProcessor.run(HttpRequestProcessor.java:265)
"http1-w1 [container1-16]" prio=10 tid=0x0000000100aa7680 nid=0x3a waiting for monitor entry [0xffffffff57afe000..
0xffffffff57aff8a8]
at jeus_jspwork._600_thead_5fmw_5fjsp._jspService(_600_thead_5fmw_5fjsp.java:64)
- waiting to lock <0xffffffff7238ca98> (a java.lang.Object)
at jeus.servlet.jsp2.runtime.HttpJspBase.service(HttpJspBase.java:106)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:818)
at jeus.servlet.jsp.JspServletWrapper.executeServlet(JspServletWrapper.java:94)
at jeus.servlet.engine.ServletWrapper.execute(ServletWrapper.java:220)
at jeus.servlet.jsp.JspServletWrapper.execute(JspServletWrapper.java:139)
at jeus.servlet.engine.HttpRequestProcessor.run(HttpRequestProcessor.java:265)
"http1-w2 [container1-15]" prio=10 tid=60000000024ffc40 nid=60 lwp_id=1583373 runnable [9fffffff786ff000..9fffffff
78700a40]
at jeus_jspwork._600_thread_5fmw_5fjsp._jspService(_600_thread_5fmw_5fjsp.java:65)
- waiting to lock <9fffffffb87909d0> (a java.lang.Object)
at jeus.servlet.jsp2.runtime.HttpJspBase.service(HttpJspBase.java:106)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:818)
at jeus.servlet.jsp.JspServletWrapper.executeServlet(JspServletWrapper.java:94)
at jeus.servlet.servlets.JspServlet.execute(JspServlet.java:359)
at jeus.servlet.engine.HttpRequestProcessor.run(HttpRequestProcessor.java:265)
"http1-w1 [container1-16]" prio=10 tid=60000000024bc480 nid=59 lwp_id=1583372 waiting for monitor entry [9fffffff7
8900000..9fffffff78900ac0]
at jeus_jspwork._600_thread_5fmw_5fjsp._jspService(_600_thread_5fmw_5fjsp.java:64)
- waiting to lock <9fffffffb87909d0> (a java.lang.Object)
at jeus.servlet.jsp2.runtime.HttpJspBase.service(HttpJspBase.java:106)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:818)
at jeus.servlet.jsp.JspServletWrapper.executeServlet(JspServletWrapper.java:94)
at jeus.servlet.engine.ServletWrapper.execute(ServletWrapper.java:220)
at jeus.servlet.jsp.JspServletWrapper.execute(JspServletWrapper.java:139)
at jeus.servlet.engine.HttpRequestProcessor.run(HttpRequestProcessor.java:265)
"http1-w0 [container1-13]" prio=10 tid=60000000024b6180 nid=58 lwp_id=1583371 waiting for monitor entry [9fffffff7
8b00000..9fffffff78b00d40]
at jeus_jspwork._600_thread_5fmw_5fjsp._jspService(_600_thread_5fmw_5fjsp.java:64)
- waiting to lock <9fffffffb87909d0> (a java.lang.Object)
at jeus.servlet.jsp2.runtime.HttpJspBase.service(HttpJspBase.java:106)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:818)
at jeus.servlet.jsp.JspServletWrapper.executeServlet(JspServletWrapper.java:94)
at jeus.servlet.engine.ServletWrapper.execute(ServletWrapper.java:220)
at jeus.servlet.jsp.JspServletWrapper.execute(JspServletWrapper.java:139)
at jeus.servlet.engine.HttpRequestProcessor.run(HttpRequestProcessor.java:265)
▶결과설명: 동기화블록진입순서대로, w2는‘runnable’으로표시되고, w0과 w1 Thread는‘waiting for monitor entry’로표시된다. 이는 SunOS 플랫폼에서와마찬가지로 HotSpot계열의 JVM을사용하기때문에매우유사하다.
[AIX / JDK 1.5]
lThread 실행순서 : w2 à w1 à w0
lDump 내용
3XMTHREADINFO "http1-w0" (TID:0x0000000114948E00, sys_thread_t:0x00000001146DE4D0, state:B, native ID:0x00000000000D00E7) prio=5
4XESTACKTRACE at jeus_jspwork/_600_thread_5fmw_5fjsp._jspService(_600_thread_5fmw_5fjsp.java:63(Compiled Code))
4XESTACKTRACE at jeus/servlet/jsp2/runtime/HttpJspBase.service(HttpJspBase.java:106)
4XESTACKTRACE at javax/servlet/http/HttpServlet.service(HttpServlet.java:818)
4XESTACKTRACE at jeus/servlet/jsp/JspServletWrapper.executeServlet(JspServletWrapper.java:94)
4XESTACKTRACE at jeus/servlet/engine/ServletWrapper.execute(ServletWrapper.java:220)
4XESTACKTRACE at jeus/servlet/jsp/JspServletWrapper.execute(JspServletWrapper.java:139)
4XESTACKTRACE at jeus/servlet/engine/HttpRequestProcessor.run(HttpRequestProcessor.java:265)
3XMTHREADINFO "http1-w1" (TID:0x0000000114A91900, sys_thread_t:0x00000001149E9F70, state:B, native ID:0x00000000001AA06F) prio=5
4XESTACKTRACE at jeus_jspwork/_600_thread_5fmw_5fjsp._jspService(_600_thread_5fmw_5fjsp.java:63)
4XESTACKTRACE at jeus/servlet/jsp2/runtime/HttpJspBase.service(HttpJspBase.java:106)
4XESTACKTRACE at javax/servlet/http/HttpServlet.service(HttpServlet.java:818)
4XESTACKTRACE at jeus/servlet/jsp/JspServletWrapper.executeServlet(JspServletWrapper.java:94)
4XESTACKTRACE at jeus/servlet/engine/ServletWrapper.execute(ServletWrapper.java:220)
4XESTACKTRACE at jeus/servlet/jsp/JspServletWrapper.execute(JspServletWrapper.java:139)
4XESTACKTRACE at jeus/servlet/engine/HttpRequestProcessor.run(HttpRequestProcessor.java:265)
3XMTHREADINFO "http1-w2" (TID:0x0000000114CC6000, sys_thread_t:0x00000001149EA450, state:CW, native ID:0x00000000001460CB) prio=5
4XESTACKTRACE at jeus_jspwork/_600_thread_5fmw_5fjsp._jspService(_600_thread_5fmw_5fjsp.java:64)
4XESTACKTRACE at jeus/servlet/jsp2/runtime/HttpJspBase.service(HttpJspBase.java:106)
4XESTACKTRACE at javax/servlet/http/HttpServlet.service(HttpServlet.java:818)
4XESTACKTRACE at jeus/servlet/jsp/JspServletWrapper.executeServlet(JspServletWrapper.java:94)
4XESTACKTRACE at jeus/servlet/servlets/JspServlet.execute(JspServlet.java:359)
4XESTACKTRACE at jeus/servlet/engine/HttpRequestProcessor.run(HttpRequestProcessor.java:265)
▶결과설명: 첫번째 Thread인 w2는동기화블록진입후‘state:CW’상태가되었고, w1과 w0은 Monitor에대한 Lock을기다리면서‘state:B’로변하는것을볼수있다.
[AIX / JDK 1.4]
lThread 실행순서 : w1 à w2 à w0
lDump 내용
3XMTHREADINFO "http1-w2" (TID:0x3031E040, sys_thread_t:0x387295A8, state:CW, native ID:0x393C) prio=5
4XESTACKTRACE at jeus_jspwork._500_thread_5fmw_5fjsp._jspService(_500_thread_5fmw_5fjsp.java(Compiled Code))
4XESTACKTRACE at jeus.servlet.jsp.HttpJspBase.service(HttpJspBase.java:53)
4XESTACKTRACE at javax.servlet.http.HttpServlet.service(HttpServlet.java:856)
4XESTACKTRACE at jeus.servlet.jsp.JspServletWrapper.executeServlet(JspServletWrapper.java:94)
4XESTACKTRACE at jeus.servlet.engine.ServletWrapper.execute(ServletWrapper.java:213)
4XESTACKTRACE at jeus.servlet.jsp.JspServletWrapper.execute(JspServletWrapper.java:140)
4XESTACKTRACE at jeus.servlet.engine.HttpRequestProcessor.run(HttpRequestProcessor.java:251)
3XHNATIVESTACK Native Stack
NULL ------------
3XHSTACKLINE at 0x38EC9E24 in
3XHSTACKLINE at 0xD012316C in _event_wait
3XHSTACKLINE at 0xD012E9DC in _cond_wait_local
3XHSTACKLINE at 0xD012EEB0 in _cond_wait
3XHSTACKLINE at 0xD012F874 in pthread_cond_timedwait
3XHSTACKLINE at 0xD22A6A10 in condvarTimedWaitUpTo248Days
3XHSTACKLINE at 0xD22A6BA0 in condvarTimedWait
3XHSTACKLINE at 0xD22A5988 in sysMonitorWait
3XHSTACKLINE at 0xD21604F4 in lkMonitorEnter
3XHSTACKLINE at 0xD2318F08 in _jit_monitorEnterQuicker
3XHSTACKLINE at 0xD2509220 in JITSigSegvHandler
3XHSTACKLINE at 0x353396E4 in
3XHSTACKLINE at 0x353396E4 in
3XMTHREADINFO "http1-w1" (TID:0x3031E150, sys_thread_t:0x38726F28, state:R, native ID:0x383B) prio=5
4XESTACKTRACE at jeus_jspwork._500_thread_5fmw_5fjsp._jspService(_500_thread_5fmw_5fjsp.java(Compiled Code))
4XESTACKTRACE at jeus.servlet.jsp.HttpJspBase.service(HttpJspBase.java:53)
4XESTACKTRACE at javax.servlet.http.HttpServlet.service(HttpServlet.java:856)
4XESTACKTRACE at jeus.servlet.jsp.JspServletWrapper.executeServlet(JspServletWrapper.java:94)
4XESTACKTRACE at jeus.servlet.servlets.JspServlet.execute(JspServlet.java:359)
4XESTACKTRACE at jeus.servlet.engine.HttpRequestProcessor.run(HttpRequestProcessor.java:251)
3XHNATIVESTACK Native Stack
NULL ------------
3XHSTACKLINE at 0x38E45390 in
3XMTHREADINFO "http1-w0 [container1-13]" (TID:0x3031BDD0, sys_thread_t:0x38726928, state:CW, native ID:0x373A) prio=5
4XESTACKTRACE at jeus_jspwork._500_thread_5fmw_5fjsp._jspService(_500_thread_5fmw_5fjsp.java(Compiled Code))
4XESTACKTRACE at jeus.servlet.jsp.HttpJspBase.service(HttpJspBase.java:53)
4XESTACKTRACE at javax.servlet.http.HttpServlet.service(HttpServlet.java:856)
4XESTACKTRACE at jeus.servlet.jsp.JspServletWrapper.executeServlet(JspServletWrapper.java:94)
4XESTACKTRACE at jeus.servlet.engine.ServletWrapper.execute(ServletWrapper.java:213)
4XESTACKTRACE at jeus.servlet.jsp.JspServletWrapper.execute(JspServletWrapper.java:140)
4XESTACKTRACE at jeus.servlet.engine.HttpRequestProcessor.run(HttpRequestProcessor.java:251)
3XHNATIVESTACK Native Stack
NULL ------------
3XHSTACKLINE at 0x38D43804 in
3XHSTACKLINE at 0xD012316C in _event_wait
3XHSTACKLINE at 0xD012E9DC in _cond_wait_local
3XHSTACKLINE at 0xD012EEB0 in _cond_wait
3XHSTACKLINE at 0xD012F874 in pthread_cond_timedwait
3XHSTACKLINE at 0xD22A6A10 in condvarTimedWaitUpTo248Days
3XHSTACKLINE at 0xD22A6BA0 in condvarTimedWait
3XHSTACKLINE at 0xD22A5988 in sysMonitorWait
3XHSTACKLINE at 0xD21604F4 in lkMonitorEnter
3XHSTACKLINE at 0xD2318F08 in _jit_monitorEnterQuicker
3XHSTACKLINE at 0xD2509220 in JITSigSegvHandler
3XHSTACKLINE at 0x353396E4 in
3XHSTACKLINE at 0x353396E4 in
▶결과설명: 첫번째 Thread인 w1는동기화블록진입후‘state:R’상태가되었고, w2과 w0은 Monitor에대한 Lock을기다리면서, ‘state:CW’로변하였다.
■Condition Wait 상태
조건대기상태로도표현되는 CW는, 흔히 Thread가동기화블록안에있거나, 혹은 Thread.sleep, object.wait()상태에머물면서 event를기다리는상황에서감지가된다.
"http1-w2" prio=10 tid=0x000000010140f2c0 nid=0x3b runnable [0xffffffff578fe000..0xffffffff578ff928]
at jeus_jspwork._600_thread_5fcw_5fjsp._jspService(_600_thread_5fcw_5fjsp.java:76)
at jeus.servlet.jsp2.runtime.HttpJspBase.service(HttpJspBase.java:106)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:818)
at jeus.servlet.jsp.JspServletWrapper.executeServlet(JspServletWrapper.java:94)
at jeus.servlet.engine.ServletWrapper.execute(ServletWrapper.java:220)
at jeus.servlet.jsp.JspServletWrapper.execute(JspServletWrapper.java:139)
at jeus.servlet.engine.HttpRequestProcessor.run(HttpRequestProcessor.java:265)
"http1-w1" prio=10 tid=0x0000000100aa7680 nid=0x3a in Object.wait() [0xffffffff57afe000..0xffffffff57aff8a8]
at java.lang.Object.wait(Native Method)
- waiting on <0xffffffff7211db78> (a java.lang.Object)
at jeus_jspwork._600_thread_5fcw_5fjsp._jspService(_600_thread_5fcw_5fjsp.java:69)
- locked <0xffffffff7211db78> (a java.lang.Object)
at jeus.servlet.jsp2.runtime.HttpJspBase.service(HttpJspBase.java:106)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:818)
at jeus.servlet.jsp.JspServletWrapper.executeServlet(JspServletWrapper.java:94)
at jeus.servlet.engine.ServletWrapper.execute(ServletWrapper.java:220)
at jeus.servlet.jsp.JspServletWrapper.execute(JspServletWrapper.java:139)
at jeus.servlet.engine.HttpRequestProcessor.run(HttpRequestProcessor.java:265)
"http1-w0 [container1-13]" prio=10 tid=0x0000000101196f40 nid=0x39 in Object.wait() [0xffffffff57cfe000..0xfffffff
f57cff828]
at java.lang.Object.wait(Native Method)
- waiting on <0xffffffff7211db78> (a java.lang.Object)
at jeus_jspwork._600_thread_5fcw_5fjsp._jspService(_600_thread_5fcw_5fjsp.java:69)
- locked <0xffffffff7211db78> (a java.lang.Object)
at jeus.servlet.jsp2.runtime.HttpJspBase.service(HttpJspBase.java:106)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:818)
at jeus.servlet.jsp.JspServletWrapper.executeServlet(JspServletWrapper.java:94)
at jeus.servlet.servlets.JspServlet.execute(JspServlet.java:359)
at jeus.servlet.engine.HttpRequestProcessor.run(HttpRequestProcessor.java:265)
"http1-w2" prio=3 tid=60000000024ffc40 nid=60 lwp_id=1583373 runnable [9fffffff786ff000..9fffffff78700a40]
at jeus_jspwork._600_thread_5fcw_5fjsp._jspService(_600_thread_5fcw_5fjsp.java:76)
at jeus.servlet.jsp2.runtime.HttpJspBase.service(HttpJspBase.java:106)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:818)
at jeus.servlet.jsp.JspServletWrapper.executeServlet(JspServletWrapper.java:94)
at jeus.servlet.engine.ServletWrapper.execute(ServletWrapper.java:220)
at jeus.servlet.jsp.JspServletWrapper.execute(JspServletWrapper.java:139)
at jeus.servlet.engine.HttpRequestProcessor.run(HttpRequestProcessor.java:265)
"http1-w1" prio=10 tid=60000000024bc480 nid=59 lwp_id=1583372 in Object.wait() [9fffffff78900000..9fffffff78900ac0
]
at java.lang.Object.wait(Native Method)
- waiting on <9fffffffb86c5a20> (a java.lang.Object)
at jeus_jspwork._600_thread_5fcw_5fjsp._jspService(_600_thread_5fcw_5fjsp.java:69)
- locked <9fffffffb86c5a20> (a java.lang.Object)
at jeus.servlet.jsp2.runtime.HttpJspBase.service(HttpJspBase.java:106)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:818)
at jeus.servlet.jsp.JspServletWrapper.executeServlet(JspServletWrapper.java:94)
at jeus.servlet.engine.ServletWrapper.execute(ServletWrapper.java:220)
at jeus.servlet.jsp.JspServletWrapper.execute(JspServletWrapper.java:139)
at jeus.servlet.engine.HttpRequestProcessor.run(HttpRequestProcessor.java:265)
"http1-w0 [container1-13]" prio=10 tid=60000000024b6180 nid=58 lwp_id=1583371 in Object.wait() [9fffffff78b00000..
9fffffff78b00d40]
at java.lang.Object.wait(Native Method)
- waiting on <9fffffffb86c5a20> (a java.lang.Object)
at jeus_jspwork._600_thread_5fcw_5fjsp._jspService(_600_thread_5fcw_5fjsp.java:69)
- locked <9fffffffb86c5a20> (a java.lang.Object)
at jeus.servlet.jsp2.runtime.HttpJspBase.service(HttpJspBase.java:106)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:818)
at jeus.servlet.jsp.JspServletWrapper.executeServlet(JspServletWrapper.java:94)
at jeus.servlet.servlets.JspServlet.execute(JspServlet.java:359)
at jeus.servlet.engine.HttpRequestProcessor.run(HttpRequestProcessor.java:265)
▶결과설명: 역시 SunOS플랫폼의결과와유사하게나타난다.
[AIX / JDK 1.5]
lThread 실행순서 : w2 à w1 à w0
lDump 내용
3XMTHREADINFO "http1-w0 [container1-15]" (TID:0x0000000114B88000, sys_thread_t:0x00000001147E06D0, state:CW, native ID:0x000000
00003230B3) prio=5
4XESTACKTRACE at jeus_jspwork/_600_thread_5fcw_5fjsp._jspService(_600_thread_5fcw_5fjsp.java:75)
4XESTACKTRACE at jeus/servlet/jsp2/runtime/HttpJspBase.service(HttpJspBase.java:106)
4XESTACKTRACE at javax/servlet/http/HttpServlet.service(HttpServlet.java:818)
4XESTACKTRACE at jeus/servlet/jsp/JspServletWrapper.executeServlet(JspServletWrapper.java:94)
4XESTACKTRACE at jeus/servlet/engine/ServletWrapper.execute(ServletWrapper.java:220)
4XESTACKTRACE at jeus/servlet/jsp/JspServletWrapper.execute(JspServletWrapper.java:139)
4XESTACKTRACE at jeus/servlet/engine/HttpRequestProcessor.run(HttpRequestProcessor.java:265)
3XMTHREADINFO "http1-w1 [container1-14]" (TID:0x0000000114C76E00, sys_thread_t:0x0000000114B88F30, state:CW, native ID:0x000000
00003DD0E7) prio=5 4XESTACKTRACE at java/lang/Object.wait(Native Method)
4XESTACKTRACE at java/lang/Object.wait(Object.java:231)
4XESTACKTRACE at jeus_jspwork/_600_thread_5fcw_5fjsp._jspService(_600_thread_5fcw_5fjsp.java:68)
4XESTACKTRACE at jeus/servlet/jsp2/runtime/HttpJspBase.service(HttpJspBase.java:106)
4XESTACKTRACE at javax/servlet/http/HttpServlet.service(HttpServlet.java:818)
4XESTACKTRACE at jeus/servlet/jsp/JspServletWrapper.executeServlet(JspServletWrapper.java:94)
4XESTACKTRACE at jeus/servlet/engine/ServletWrapper.execute(ServletWrapper.java:220)
4XESTACKTRACE at jeus/servlet/jsp/JspServletWrapper.execute(JspServletWrapper.java:139)
4XESTACKTRACE at jeus/servlet/engine/HttpRequestProcessor.run(HttpRequestProcessor.java:265)
3XMTHREADINFO "http1-w2 [container1-13]" (TID:0x0000000114C7B600, sys_thread_t:0x0000000114B89410, state:CW, native ID:0x000000
00003E00DB) prio=5 4XESTACKTRACE at java/lang/Object.wait(Native Method)
4XESTACKTRACE at java/lang/Object.wait(Object.java:231)
4XESTACKTRACE at jeus_jspwork/_600_thread_5fcw_5fjsp._jspService(_600_thread_5fcw_5fjsp.java:68)
4XESTACKTRACE at jeus/servlet/jsp2/runtime/HttpJspBase.service(HttpJspBase.java:106)
4XESTACKTRACE at javax/servlet/http/HttpServlet.service(HttpServlet.java:818)
4XESTACKTRACE at jeus/servlet/jsp/JspServletWrapper.executeServlet(JspServletWrapper.java:94)
4XESTACKTRACE at jeus/servlet/servlets/JspServlet.execute(JspServlet.java:359)
4XESTACKTRACE at jeus/servlet/engine/HttpRequestProcessor.run(HttpRequestProcessor.java:265)
"http1-w1" prio=10 tid=0x00000001003d1cc0 nid=0x3a waiting for monitor entry [0xffffffff57afe000..0xffffffff57aff6
28] at jeus_jspwork._600_thread_5fdeadlock_5fjsp._jspService(_600_thread_5fdeadlock_5fjsp.java:70)
- waiting to lock <0xffffffff71857638> (a java.lang.Object)
- locked <0xffffffff71857628> (a java.lang.Object)
at jeus.servlet.jsp2.runtime.HttpJspBase.service(HttpJspBase.java:106)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:818)
at jeus.servlet.jsp.JspServletWrapper.executeServlet(JspServletWrapper.java:94)
at jeus.servlet.engine.ServletWrapper.execute(ServletWrapper.java:220)
at jeus.servlet.jsp.JspServletWrapper.execute(JspServletWrapper.java:139)
at jeus.servlet.engine.HttpRequestProcessor.run(HttpRequestProcessor.java:265)
"http1-w0 [container1-13]" prio=10 tid=0x00000001003d1950 nid=0x39 waiting for monitor entry [0xffffffff57cfe000..
0xffffffff57cff6a8]
at jeus_jspwork._600_thread_5fdeadlock_5fjsp._jspService(_600_thread_5fdeadlock_5fjsp.java:77)
- waiting to lock <0xffffffff71857628> (a java.lang.Object)
- locked <0xffffffff71857638> (a java.lang.Object)
at jeus.servlet.jsp2.runtime.HttpJspBase.service(HttpJspBase.java:106)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:818)
at jeus.servlet.jsp.JspServletWrapper.executeServlet(JspServletWrapper.java:94)
at jeus.servlet.servlets.JspServlet.execute(JspServlet.java:359)
at jeus.servlet.engine.HttpRequestProcessor.run(HttpRequestProcessor.java:265)
▶결과설명: 각각의 Thread는, for문안에서서로의객체에대한 Monitor를기다리면서동기화블록안으로진입을대기하고있음으로,‘waiting for monitor entry’로표시된다.
Stack 정보에는, 해당 Thread가‘0xffffffff71857638’와‘0xffffffff71857628’를Locked하고있는정보를볼수있다.
[HP-UX]
"http1-w2 [container1-15]" prio=10 tid=60000000024ffc40 nid=60 lwp_id=1583373 waiting for monitor entry [9fffffff7
8700000..9fffffff78700a40]
at jeus_jspwork._600_thread_5fdeadlock_5fjsp._jspService(_600_thread_5fdeadlock_5fjsp.java:77)
- waiting to lock <9fffffffb8cde050> (a java.lang.Object)
- locked <9fffffffb8cde060> (a java.lang.Object)
at jeus.servlet.jsp2.runtime.HttpJspBase.service(HttpJspBase.java:106)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:818)
at jeus.servlet.jsp.JspServletWrapper.executeServlet(JspServletWrapper.java:94)
at jeus.servlet.servlets.JspServlet.execute(JspServlet.java:359)
at jeus.servlet.engine.HttpRequestProcessor.run(HttpRequestProcessor.java:265)
"http1-w1 [container1-16]" prio=10 tid=60000000024bc480 nid=59 lwp_id=1583372 waiting for monitor entry [9fffffff7
8900000..9fffffff78900ac0]
at jeus_jspwork._600_thread_5fdeadlock_5fjsp._jspService(_600_thread_5fdeadlock_5fjsp.java:70)
- waiting to lock <9fffffffb8cde060> (a java.lang.Object)
- locked <9fffffffb8cde050> (a java.lang.Object)
at jeus.servlet.jsp2.runtime.HttpJspBase.service(HttpJspBase.java:106)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:818)
at jeus.servlet.jsp.JspServletWrapper.executeServlet(JspServletWrapper.java:94)
at jeus.servlet.engine.ServletWrapper.execute(ServletWrapper.java:220)
at jeus.servlet.jsp.JspServletWrapper.execute(JspServletWrapper.java:139)
at jeus.servlet.engine.HttpRequestProcessor.run(HttpRequestProcessor.java:265)
▶결과설명: SunOS와거의유사한패턴을보이고있다.
[AIX / JDK 1.5]
lThread 실행순서 : w1 à w2 à w0
lDump 내용
3XMTHREADINFO "http1-w0 [container1-13]" (TID:0x0000000114A07100, sys_thread_t:0x00000001147764F0, state:B, native ID:0x0000000
000372005) prio=5
4XESTACKTRACE at jeus_jspwork/_600_thread_5fdeadlock_5fjsp._jspService(_600_thread_5fdeadlock_5fjsp.java:76)
4XESTACKTRACE at jeus/servlet/jsp2/runtime/HttpJspBase.service(HttpJspBase.java:106)
4XESTACKTRACE at javax/servlet/http/HttpServlet.service(HttpServlet.java:818)
4XESTACKTRACE at jeus/servlet/jsp/JspServletWrapper.executeServlet(JspServletWrapper.java:94)
4XESTACKTRACE at jeus/servlet/servlets/JspServlet.execute(JspServlet.java:359)
4XESTACKTRACE at jeus/servlet/engine/HttpRequestProcessor.run(HttpRequestProcessor.java:265)
3XMTHREADINFO "http1-w1 [container1-14]" (TID:0x0000000114A15C00, sys_thread_t:0x0000000114A11350, state:B, native ID:0x0000000
0003D00BD) prio=5
4XESTACKTRACE at jeus_jspwork/_600_thread_5fdeadlock_5fjsp._jspService(_600_thread_5fdeadlock_5fjsp.java:69(Compiled Code))
4XESTACKTRACE at jeus/servlet/jsp2/runtime/HttpJspBase.service(HttpJspBase.java:106)
4XESTACKTRACE at javax/servlet/http/HttpServlet.service(HttpServlet.java:818)
4XESTACKTRACE at jeus/servlet/jsp/JspServletWrapper.executeServlet(JspServletWrapper.java:94)
4XESTACKTRACE at jeus/servlet/engine/ServletWrapper.execute(ServletWrapper.java:220)
4XESTACKTRACE at jeus/servlet/jsp/JspServletWrapper.execute(JspServletWrapper.java:139)
4XESTACKTRACE at jeus/servlet/engine/HttpRequestProcessor.run(HttpRequestProcessor.java:265)
3XMTHREADINFO "http1-w2" (TID:0x0000000114C6C300, sys_thread_t:0x0000000114A11830, state:P, native ID:0x000000000008B031) prio=
5
4XESTACKTRACE at sun/misc/Unsafe.park(Native Method)
4XESTACKTRACE at java/util/concurrent/locks/LockSupport.park(LockSupport.java:169)
4XESTACKTRACE at java/util/concurrent/locks/AbstractQueuedSynchronizer$ConditionObject.await(AbstractQueuedSynchronizer.jav
a:1793)
4XESTACKTRACE at java/util/concurrent/LinkedBlockingQueue.take(LinkedBlockingQueue.java:379)
4XESTACKTRACE at jeus/servlet/util/StandardQueue.get(StandardQueue.java:53)
4XESTACKTRACE at jeus/servlet/engine/ThreadPoolManager.getConnection(ThreadPoolManager.java:332)
4XESTACKTRACE at jeus/servlet/engine/HttpRequestProcessor.run(HttpRequestProcessor.java:95)
▶결과설명: java.util.concurrent 관련한클래스들이작동하고있는모습이보인다.
이경우, Dump Header 부분에서아래와같은메시지가같이출력된다.
1LKDEADLOCK Deadlock detected !!!
NULL ---------------------
NULL
2LKDEADLOCKTHR Thread "http1-w0 [container1-13]" (0x0000000114A07100)
3LKDEADLOCKWTR is waiting for:
4LKDEADLOCKMON sys_mon_t:0x0000000112E0C9E0 infl_mon_t: 0x0000000112E0CA30:
4LKDEADLOCKOBJ java/lang/Object@0700000002309EF8/0700000002309F10:
3LKDEADLOCKOWN which is owned by:
2LKDEADLOCKTHR Thread "http1-w1 [container1-14]" (0x0000000114A15C00)
3LKDEADLOCKWTR which is waiting for:
4LKDEADLOCKMON sys_mon_t:0x000000011498DA00 infl_mon_t: 0x000000011498DA50:
4LKDEADLOCKOBJ java/lang/Object@0700000002309F10/0700000002309F28:
3LKDEADLOCKOWN which is owned by:
2LKDEADLOCKTHR Thread "http1-w0 [container1-13]" (0x0000000114A07100)
[AIX / JDK 1.4]
lThread 실행순서 : w1 à w2 à w0
lDump 내용
3XMTHREADINFO "http1-w1" (TID:0x304F7768, sys_thread_t:0x38E21528, state:CW, native ID:0x383B) prio=5
4XESTACKTRACE at jeus_jspwork._500_thread_5fdeadlock_5fjsp._jspService(_500_thread_5fdeadlock_5fjsp.java(Compiled Code))
4XESTACKTRACE at jeus.servlet.jsp.HttpJspBase.service(HttpJspBase.java:53)
4XESTACKTRACE at javax.servlet.http.HttpServlet.service(HttpServlet.java:856)
4XESTACKTRACE at jeus.servlet.jsp.JspServletWrapper.executeServlet(JspServletWrapper.java:94)
4XESTACKTRACE at jeus.servlet.engine.ServletWrapper.execute(ServletWrapper.java:213)
4XESTACKTRACE at jeus.servlet.jsp.JspServletWrapper.execute(JspServletWrapper.java:140)
4XESTACKTRACE at jeus.servlet.engine.HttpRequestProcessor.run(HttpRequestProcessor.java:251)
3XHNATIVESTACK Native Stack
NULL ------------
3XHSTACKLINE at 0x38EE6804 in
3XHSTACKLINE at 0xD012316C in _event_wait
3XHSTACKLINE at 0xD012E9DC in _cond_wait_local
3XHSTACKLINE at 0xD012EEB0 in _cond_wait
3XHSTACKLINE at 0xD012F874 in pthread_cond_timedwait
3XHSTACKLINE at 0xD22A6A10 in condvarTimedWaitUpTo248Days
3XHSTACKLINE at 0xD22A6BA0 in condvarTimedWait
3XHSTACKLINE at 0xD22A5988 in sysMonitorWait
3XHSTACKLINE at 0xD21604F4 in lkMonitorEnter
3XHSTACKLINE at 0xD2318F08 in _jit_monitorEnterQuicker
3XHSTACKLINE at 0xD2509220 in JITSigSegvHandler
3XHSTACKLINE at 0x35339254 in
3XHSTACKLINE at 0x35339254 in
3XMTHREADINFO "http1-w0" (TID:0x304C93B0, sys_thread_t:0x38E20F28, state:MW, native ID:0x373A) prio=5
4XESTACKTRACE at jeus_jspwork._500_thread_5fdeadlock_5fjsp._jspService(_500_thread_5fdeadlock_5fjsp.java(Compiled Code))
4XESTACKTRACE at jeus.servlet.jsp.HttpJspBase.service(HttpJspBase.java:53)
4XESTACKTRACE at javax.servlet.http.HttpServlet.service(HttpServlet.java:856)
4XESTACKTRACE at jeus.servlet.jsp.JspServletWrapper.executeServlet(JspServletWrapper.java:94)
4XESTACKTRACE at jeus.servlet.servlets.JspServlet.execute(JspServlet.java:359)
4XESTACKTRACE at jeus.servlet.engine.HttpRequestProcessor.run(HttpRequestProcessor.java:251)
3XHNATIVESTACK Native Stack
NULL ------------
3XHSTACKLINE at 0xD230F26C in release_m_block
3XHSTACKLINE at 0xD011D4A4 in _mutex_lock
3XHSTACKLINE at 0xD22A66E4 in cooperative_mutex_lock
3XHSTACKLINE at 0xD22A6334 in sysMonitorEnter
3XHSTACKLINE at 0xD21604F4 in lkMonitorEnter
3XHSTACKLINE at 0xD2318F08 in _jit_monitorEnterQuicker
3XHSTACKLINE at 0xD2509220 in JITSigSegvHandler
3XHSTACKLINE at 0x35339254 in
이것땜에 오늘 또 하루를 날렸다.. 바쁜때에는 꼭 예상 밖의 일들이 터져서 하루를 피곤하게 만든다.
며칠 전부터, 개발서버 AIX 환경에서 매 요청 마다 Exception 이 계속 발생했는데,
대충, Struts2 의 FileUploaderInterceptor 에서 부터 시작하고, 결국에는 NoSuchFieldException 을 throw 하게 되는 콜스택을 보이는 예외이다.
사실 동작하는데 크게 문제는 없지만, 여간 신경쓰이는게 아니어서 해결하려고, Struts2 와 내부에서 사용하는 xwork2 의 소스까지 빌드해가면서 찾아낸 결론은,
AIX 에서는 IBM JDK (JDK6) 와 xwork 와의 호환성에 문제가 있어,
struts.xml 이나 properties 에서, struts.i18n.reload 와 devmode 옵션을 false 로 주어야 한다
는 것이다.
좀더 깊숙히 원인을 분석해본 결과, struts2 가 사용하는 xwork2 라이브러리에서, ResourceBundle 을 사용하는데,
Struts 의 Dispatcher 에서 사용하는 xwork 의 클래스 중에서 (LocalizedText 였나.. 기억이..) java.util.ResourceBundle 을 사용한다.
이때, xwork 의 옵션으로, 리소스를 동적으로 갱신 시에 리로드 할 수 있는 옵션을 줄 수 있는데, struts2 에서는 Dispatcher 에서 struts.i18n.reload 옵션값을 읽어, xwork 에 설정하도록 한다.
이때 reload 옵션이 true 인 경우, 위와 같은 문제가 생기는데, 옵션이 true 이면, ResourceBundle 의 claerCache() 메소드를 호출하거나 하는게 아니라, Reflection 기능을 사용하여, ResourceBundle 의 내부 HashMap, 그것도 private 로 선언된 놈(멤버변수명: cacheList) 을 setAccessible(true)를 써가면서 까지 가져와 직접 clear() 를 호출하도록 하고 있다.
여기에서 문제가 생기는데, Sun 의 JDK 의 경우, 위 map 의 변수명이 cacheList 이지만, IBM 의 JDK 의 구현 소스는 내부적으로 많이 다르고, cacheList 라는 Field 변수 자체가 없다. 그래서 오류가 나는 것이다.
이 기능을 안쓰거나, xwork 소스를 수정하는 방법이 있겠는데, 나는 회피하는 방법을 쓰려고 struts.i18n.reload 를 false 로 struts.xml 의 constant 선언으로 값을 주었지만 먹지를 않았다. 그래서 결국 xwork 와 struts 를 소스로 받아 세팅값이 먹혔는지 보기 위해 maven 으로 빌드까지 해가면서 파악 해보니, struts.i18n.reload 값에 앞서, devmode 를 false 로 해줘야 하는것을 알 수 있었다.
결국은 저렇게 세팅하나 잘못 바꿔서 하루를 날려버리는 참 어처구니 없는 일을 저지르고 말았다..
그래도 Reflection 의 강력한 기능과 Struts2 의 내부를 조금이나마 더 들여다 볼 수 있는 기회이기도 했다는데에 만족하고 있다.