HttpSessionBindingListener.valueUnbound 未在会话超时时触发

HttpSessionBindingListener.valueUnbound is not triggered on session timeout

我们需要在会话超时时进行一些数据库清理,因此实现了 HttpSessionBindingListener 并在用户登录时向会话添加了一个对象,我们从不明确地将其从会话中删除。

HttpSessionBindingListener.valueUnbound 如果我们手动调用 session.invalidate 会触发,但问题是它不会在会话超时时触发。我在控制台中看到一个错误,但不确定是什么问题。

在登录时将对象设置为会话并在注销时使会话无效:

@Named("logincontroller")
@Stateful
public class LoginController implements ILoginController, Serializable {

  @Inject
  private Credentials credentials;
  private ExternalContext ec = null;
  private HttpServletRequest request =null;
  private HttpServletResponse response=null;
  private HttpSession session=null;

  @PostConstruct
  private void getLocalVariables() {
    ec = FacesContext.getCurrentInstance().getExternalContext();
    request= (HttpServletRequest)ec.getRequest();
    session = request.getSession();
  }

  @Override
  public boolean login() {
    ... 
    credentials.setUserName(getUserName().toUpperCase());
    credentials.setUserPassword(getPassword());
    // set the object into session on user login
    session.setAttribute("credentials", credentials); 
  }

  @Override
  public void logout() {
        ...
        try {
            response.sendRedirect(path+"/faces/Exit.html");
            // invalidate the session on logout
            session.invalidate(); 
        } catch (Exception ex) {
            ex.printStackTrace();
        }
    }
  }
}

实现 HttpSessionBindingListener 的凭据对象

@Named("credentials")
@SessionScoped
public class Credentials implements ICredentials, Serializable, HttpSessionBindingListener {
  ...
  @Override
  public void valueBound(HttpSessionBindingEvent event) {
    //do nothing
  }

  @Override
  public void valueUnbound(HttpSessionBindingEvent event) {
    try {
        // run DB scripts to clean up
        lockManager.releaseAllLocksForUser(getUserName().toUpperCase()); 
    } catch (Exception e) {
        e.printStackTrace();
    }
  }
}

错误堆栈跟踪:

15:13:03,252 INFO  [org.jboss.as.repository] (ServerService Thread Pool -- 66) WFLYDR0009: Content C:<path>jbossstudio10\runtimes\jboss-eap\standalone\data\contentccffda3936daab4d3148eb2e51584f8372592 is obsolete and will be removed
15:13:03,299 INFO  [org.jboss.as.repository] (ServerService Thread Pool -- 66) WFLYDR0002: Content removed from location C:\<path>\jbossstudio10\runtimes\jboss-eap\standalone\data\contentccffda3936daab4d3148eb2e51584f8372592\content
15:26:36,245 ERROR [stderr] (default task-22) Exception in thread "default task-22" org.jboss.weld.context.ContextNotActiveException: WELD-001303: No active contexts for scope type javax.enterprise.context.SessionScoped
15:26:36,246 ERROR [stderr] (default task-22)   at org.jboss.weld.manager.BeanManagerImpl.getContext(BeanManagerImpl.java:689)
15:26:36,246 ERROR [stderr] (default task-22)   at org.jboss.weld.bean.ContextualInstanceStrategy$DefaultContextualInstanceStrategy.getIfExists(ContextualInstanceStrategy.java:90)
15:26:36,246 ERROR [stderr] (default task-22)   at org.jboss.weld.bean.ContextualInstanceStrategy$CachingContextualInstanceStrategy.getIfExists(ContextualInstanceStrategy.java:165)
15:26:36,246 ERROR [stderr] (default task-22)   at org.jboss.weld.bean.ContextualInstance.getIfExists(ContextualInstance.java:63)
15:26:36,246 ERROR [stderr] (default task-22)   at org.jboss.weld.bean.proxy.ContextBeanInstance.getInstance(ContextBeanInstance.java:83)
15:26:36,246 ERROR [stderr] (default task-22)   at org.jboss.weld.bean.proxy.ProxyMethodHandler.getInstance(ProxyMethodHandler.java:125)
15:26:36,246 ERROR [stderr] (default task-22)   at com.facility.security.Credentials$Proxy$_$$_WeldClientProxy.valueUnbound(Unknown Source) // unknown source??
15:26:36,246 ERROR [stderr] (default task-22)   at io.undertow.servlet.core.SessionListenerBridge.attributeRemoved(SessionListenerBridge.java:132)
15:26:36,247 ERROR [stderr] (default task-22)   at io.undertow.server.session.SessionListeners.attributeRemoved(SessionListeners.java:81)
15:26:36,247 ERROR [stderr] (default task-22)   at io.undertow.server.session.InMemorySessionManager$SessionImpl.removeAttribute(InMemorySessionManager.java:500)
15:26:36,247 ERROR [stderr] (default task-22)   at io.undertow.servlet.core.SessionListenerBridge.sessionDestroyed(SessionListenerBridge.java:72)
15:26:36,247 ERROR [stderr] (default task-22)   at io.undertow.server.session.SessionListeners.sessionDestroyed(SessionListeners.java:61)
15:26:36,248 ERROR [stderr] (default task-22)   at io.undertow.server.session.InMemorySessionManager$SessionImpl.invalidate(InMemorySessionManager.java:528)
15:26:36,248 ERROR [stderr] (default task-22)   at io.undertow.server.session.InMemorySessionManager$SessionImpl.run(InMemorySessionManager.java:357)
15:26:36,248 ERROR [stderr] (default task-22)   at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
15:26:36,248 ERROR [stderr] (default task-22)   at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
15:26:36,248 ERROR [stderr] (default task-22)   at java.lang.Thread.run(Thread.java:748)

我是否需要在 valueUnbound 中获取一个新会话到 运行 我的数据库脚本?我认为在调用 valueUnbound 时我们仍然有会话。我确实搜索了 Whosebug,但无济于事。

非常感谢任何帮助。 环境:Windows 7 Enterrpise,JDK 1.8,JBoss EAP 7.0.0,CDI 1.2,Mojarra 2.2.12-jbossorg-2,deltaspike 1.8.1,Servlets 3.1,PrimeFaces 6.1,甲骨文 11g

我从未真正使用过 HttpSessionBindingListener.valueUnbound,但看起来事件的顺序在 CDI 和 servlet 行为之间有点混乱。具体来说,它看起来像 CDI 被告知在调用 HttpSessionBindingListener.valueUnbound 之前拆除会话 bean。因此异常 - 当应该调用该方法时,您不再有会话上下文活动。

可能的解决方案是扭曲您的代码并且不使用 HttpSessionBindingListener.valueUnbound 而是使Credentials.valueUnbound 成为@PreDestroy 方法。这样,只要该 bean 将被销毁,CDI 就应该调用它,无论原因是会话失效还是超时。