はFacesContext、を呼び出したWebブラウザによって開始されたHTTPリクエストを処理するスレッドでのみ使用できますFacesServlet。セッションの破棄中に、必ずしもHTTPリクエストの手段があるとは限りません。セッションは通常、コンテナによって管理されるバックグラウンドスレッドによって破棄されます。これは、を介してHTTPリクエストを呼び出しませんFacesServlet。FacesContextしたがって、セッションの破棄中に常にそこにあると期待するべきではありません。session.invalidate()JSFマネージドBean内で呼び出す場合にのみ、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);
}
サーブレット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}。