问题描述
我需要访问一个应用程序范围的托管bean来修改HttpSessionListener中的某些属性。
I need to access an application-scoped managed bean to modify certain properties from within an HttpSessionListener.
我已经使用过如下内容:
I already used something like the following:
@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是否可以通过上述方式访问。
externalContext = FacesContext.getCurrentInstance().getExternalContext() causes a null pointer exception here already, and even if it didn't I'm not sure appBean could be accessible the above way.
任何想法?
推荐答案
FacesContext
仅在服务于webbrowser发起的HTTP请求的线程中可用,该请求已调用 FacesServlet的
。在会话销毁期间,不一定是HTTP请求的手段。会话通常由容器管理的后台线程销毁。这不会通过 FacesServlet
调用HTTP请求。因此,在会话销毁期间,您不应期望 FacesContext
始终存在。只有在JSF托管bean中调用 session.invalidate()
时,才能使用 FacesContext
。
The FacesContext
is only available in the thread serving the HTTP request initiated by the webbrowser which has invoked the FacesServlet
. During a session destroy there's not necessarily means of a HTTP request. Sessions are usually destroyed by a background thread managed by the container. This does not invoke a HTTP request through the FacesServlet
. So you should not expect the FacesContext
to be always there during the session destroy. Only when you call session.invalidate()
inside a JSF managed bean, then the FacesContext
is available.
如果您的应用程序作用域托管bean由JSF @ManagedBean
管理,那么很高兴知道JSF将它存储在封面下作为 ServletContext
的属性。 <$ href =http://docs.oracle.com/javaee/6/api/javax/servlet/http在会话监听器中提供 ServletContext
/HttpSession.html#getServletContext%28%29\"rel =nofollow> HttpSession#getServletContext()
。
If your application scoped managed bean is managed by JSF @ManagedBean
, then it's good to know that JSF stores it under the covers as an attribute of the ServletContext
. The ServletContext
in turn is available in the session listener by 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
属性。
If you're running a Servlet 3.0 capable container, an alternative is to just let your application scoped bean implement HttpSessionListener
and register itself as such upon construction. This way you have direct reference to the connectedUsers
property.
@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
注释来标记在销毁会话时应该调用的方法。
Again another alternative is to keep the User
in the session scope as a session scoped managed bean. You can then use the @PreDestroy
annotation to mark a method which should be invoked when the session is destroyed.
@ManagedBean
@SessionScoped
public class User {
@ManagedProperty("#{appBean}")
private AppBean appBean;
@PreDestroy
public void destroy() {
appBean.getConnectedUsers().remove(this);
}
// ...
}
这具有额外的好处,用户
在EL上下文中可用#{user}
。
This has the additional benefit that the User
is in EL context available as #{user}
.
这篇关于从会话侦听器访问和修改Application-Scoped Managed Bean的属性的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!