我需要访问一个应用程序范围的托管bean来修改HttpSessionListener中的某些属性。
我已经使用过以下内容:
@Override
public void sessionDestroyed(HttpSessionEvent se) {
HttpSession session = se.getSession();
User user = userService.findBySessionId(session.getId());
ExternalContext externalContext = FacesContext.getCurrentInstance().getExternalContext();
ApplicationScopedBean appBean = (ApplicationScopedBean) externalContext.getApplicationMap().get("appBean");
appBean.getConnectedUsers().remove(user);
}
externalContext = FacesContext.getCurrentInstance()。getExternalContext()在这里导致空指针异常,即使它没有,我也不确定appBean是否可以通过上述方式访问。
有什么想法吗?
答案 0 :(得分:3)
FacesContext
仅在服务于已调用FacesServlet
的webbrowser发起的HTTP请求的线程中可用。在会话销毁期间,不一定是HTTP请求的手段。会话通常由容器管理的后台线程销毁。这不会通过FacesServlet
调用HTTP请求。因此,您不应期望FacesContext
在会话销毁期间始终存在。只有当您在JSF托管bean中调用session.invalidate()
时,FacesContext
才可用。
如果您的应用程序作用域托管bean由JSF @ManagedBean
管理,那么最好知道JSF将它作为ServletContext
的属性存储在封面下。 ServletContext
依次由HttpSession#getServletContext()
在会话监听器中提供。
所以,这应该做:
@Override
public void sessionDestroyed(HttpSessionEvent se) {
HttpSession session = se.getSession();
User user = userService.findBySessionId(session.getId());
ApplicationScopedBean appBean = (ApplicationScopedBean) session.getServletContext().getAttribute("appBean");
appBean.getConnectedUsers().remove(user);
}
如果您正在运行支持Servlet 3.0的容器,另一种方法是让您的应用程序使用作用域bean HttpSessionListener
并在构造时自行注册。这样您就可以直接引用connectedUsers
属性。
@ManagedBean
@ApplicationScoped
public class AppBean implements HttpSessionListener {
public AppBean() {
ServletContext context = (ServletContext) FacesContext.getCurrentInstance().getExternalContext().getContext();
context.addListener(this);
}
@Override
public void sessionDestroyed(HttpSessionEvent se) {
HttpSession session = se.getSession();
User user = userService.findBySessionId(session.getId());
connectedUsers.remove(user);
}
// ...
}
另一种替代方法是将User
作为会话范围的托管bean保留在会话范围中。然后,您可以使用@PreDestroy
注释来标记在销毁会话时应调用的方法。
@ManagedBean
@SessionScoped
public class User {
@ManagedProperty("#{appBean}")
private AppBean appBean;
@PreDestroy
public void destroy() {
appBean.getConnectedUsers().remove(this);
}
// ...
}
这具有额外的好处,User
在EL上下文中可用#{user}
。