我有一个Web应用程序(Servlet 2.4规范),可以在Websphere 8.0,8.5和Tomcat 8.5上正常运行。现在我们要评估是否可以在Websphere Liberty下运行应用程序。
Websphere日志文件在启动期间提供以下版本号:
product = WebSphere Application Server 17.0.0.2 (wlp-1.0.17.cl170220170523-1818)
在应用程序启动期间,通过在浏览器中发送起始URL,某些对象将绑定到会话。例如,通过以下代码:
(...)
GwgImpl gwg = (GwgImpl)session.getAttribute(WEBKEY);
if (gwg == null) {
gwg = new GwgImpl();
session.setAttribute(WEBKEY, gwg);
}
(...)
GwgImpl
对象由以下内容定义:
public class GwgImpl implements HttpSessionBindingListener {
List<String> list = new ArrayList<String>();
(...)
public void valueBound(HttpSessionBindingEvent ev) {
}
public void valueUnbound(HttpSessionBindingEvent ev) {
list.clear();
list = null;
(...)
}
(...)
}
直到现在,一切似乎都运作良好。但是当用户从应用程序注销并且我的LogoutHandler
通过以下
(...)
HttpSession session = request.getSession(false);
if (session != null) {
session.invalidate();
}
(...)
对象valueUnbound()
中的方法GwgImpl
被调用两次。由于方法的第一次调用会将变量list
设置为null
,因此第二次调用会生成NullPointerException
。
我知道我可以通过添加if语句轻松解决此问题,但由于没有其他应用程序服务器出现此问题,我有以下问题:
是否允许应用程序服务器在会话失效期间对绑定到会话的对象进行两次调用valueUnbound(..)
方法? (我还没有从servlet规范中找到明确的答案)
或者这是Websphere应用程序服务器中的错误吗?
我修改了valueUnbound(..)
方法,以查看两个调用的调用堆栈以及HttpSessionBindingEvent
的值。
public void valueUnbound(HttpSessionBindingEvent ev) {
logger.info("Stacktrace:");
for (StackTraceElement stackTraceElement : Thread.currentThread().getStackTrace()) {
logger.info(" " + stackTraceElement.toString());
}
logger.info("HttpSessionBindingEvent:");
logger.info(" SessionID='" + ev.getSession().getId() + "'");
logger.info(" Name='" + ev.getName() + "'");
logger.info(" Value='" + ev.getValue() + "'");
(...)
}
在我的Websphere日志文件中,我现在找到以下行:
Stacktrace:
java.lang.Thread.getStackTrace(Unknown Source)
com.mycorp.gwg.dao.GwgImpl.valueUnbound(GwgImpl.java:130)
com.ibm.ws.session.http.HttpSessionObserver.sessionDestroyed(HttpSessionObserver.java:231)
com.ibm.ws.session.SessionEventDispatcher.sessionDestroyed(SessionEventDispatcher.java:167)
com.ibm.ws.session.StoreCallback.sessionInvalidated(StoreCallback.java:129)
com.ibm.ws.session.store.memory.MemorySession.invalidate(MemorySession.java:236)
com.ibm.ws.session.http.HttpSessionImpl.invalidate(HttpSessionImpl.java:317)
com.ibm.ws.session.SessionData.invalidate(SessionData.java:256)
com.ibm.ws.session.HttpSessionFacade.invalidate(HttpSessionFacade.java:197)
com.mycorp.login.client.LogoutHandler.doLogout(LogoutHandler.java:154)
(...)
HttpSessionBindingEvent:
SessionID='X_AmenZHphA-DBkNRoOeWZu'
Name='gwg'
Value='null'
(...)
Stacktrace:
java.lang.Thread.getStackTrace(Unknown Source)
com.mycorp.gwg.dao.GwgImpl.valueUnbound(GwgImpl.java:130)
com.ibm.ws.session.http.HttpSessionAttributeObserver.sessionAttributeRemoved(HttpSessionAttributeObserver.java:160)
com.ibm.ws.session.SessionStateEventDispatcher.sessionAttributeRemoved(SessionStateEventDispatcher.java:142)
com.ibm.ws.session.StoreCallback.sessionAttributeRemoved(StoreCallback.java:196)
com.ibm.ws.session.store.memory.MemorySession.removeAttribute(MemorySession.java:537)
com.ibm.ws.session.store.memory.MemorySession.invalidate(MemorySession.java:253)
com.ibm.ws.session.http.HttpSessionImpl.invalidate(HttpSessionImpl.java:317)
com.ibm.ws.session.SessionData.invalidate(SessionData.java:256)
com.ibm.ws.session.HttpSessionFacade.invalidate(HttpSessionFacade.java:197)
com.mycorp.login.client.LogoutHandler.doLogout(LogoutHandler.java:154)
(...)
HttpSessionBindingEvent:
SessionID='X_AmenZHphA-DBkNRoOeWZu'
Name='gwg'
Value='com.mycorp.gwg.dao.GwgImpl@b294b7c'