从会话侦听器访问和修改Application-Scoped Managed Bean的属性
我需要访问应用程序范围的托管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()在这里导致空指针exception,即使它没有,我也不确定appBean是否可以通过上述方式访问。
有任何想法吗?
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}
。