在同一会话中多次从另一个SessionScoped bean访问SessionScoped bean会创建一个新实例

时间:2014-08-12 14:07:45

标签: session servlets cdi

我在我的应用程序中遇到了一个我不明白的行为。我有一个servlet( Servlet1 )接受请求,使当前会话无效,创建一个新会话,然后将请求重定向到引用@Named @SessionScoped bean的JSF页面( Bean1 )。 servlet和bean @Inject都是另一个@SessionScoped bean( SharedBean )。我第一次访问我的servlet URL时一切正常。但是,第二次访问URL时,@ Named @SessionScoped bean正在创建一个新的sharedbean实例。

所以我想要发生的是:

  1. Servlet1 会创建新会话
  2. Servlet1 初始化 SharedBean
  3. Bean1 访问 SharedBean
  4. 第一次访问我的servlet URL时会发生这种情况,但第二次调用时发生的情况是:

    1. Servlet1 会创建新会话
    2. Servlet1 初始化 SharedBean
    3. Bean1 创建新的 SharedBean
    4. 这对我来说似乎不是正确的行为。我知道我在这里遗漏了一些东西,我很感激有人向我解释。代码如下:

      Servlet1:

      @WebServlet
      public class Servlet1 extends HttpServlet
      {
          @Inject
          private SharedBean sbean;
      
          public doGet(HttpServeltRequest request, HttpServletResponse response)
          {
              HttpSession session = request.getSession();
              session.invalidate();
              session             = request.getSession(true);
      
              this.sbean.initialize();
      
              response.sendRedirect(newURL);
          }
      }
      

      Bean1:

      @Named
      @SessionScoped
      public class Bean1 implements Serializable
      {
          @Inject
          private SharedBean sbean;
      
          public void actionMethod()
          {
              this.sbean.execute(); // New instance being created here on 2nd access!
          }
      }
      

      SharedBean:

      @SessionScoped
      public class SharedBean implements Serializable
      {
          public void initialize() { /* do some work */ }
          public void exeucte() { /* do some work */ }
      }
      

1 个答案:

答案 0 :(得分:1)

因为每次请求servlet时都会使会话无效。所以容器创建一个新bean或提供另一个实例。在用户或某个其他端点处于非活动状态一段时间后,您必须使会话无效。

SessionScoped 表示bean实例对多个请求有效。 但您必须确定会话对您的应用程序的意义。 在大多数情况下,会话与用户登录和注销的时间相关联。所以它由多个请求组成。 因此,会话对多个请求有效,对于不同的servlet也是如此。 会话由servlet容器(例如Tomcat)管理,会话对象的实例通过 ServletContext 实例提供。

每次请求servlet时都会创建一个新会话。这意味着容器只为该单个请求创建 ServletContext ,并始终将 SharedBean 的新bean实例绑定到该上下文实例。

由于评论而更新。

在这种情况下,我不建议让容器管理bean注入。 因为您永远不知道bean实例创建和关联的时间 一个SharedBean实例。我认为原因是你在servlet请求方法中创建一个新会话的问题。在这种情况下, SharedBean 的bean实例不能相同,因为容器会创建 SharedBean 的新实例,并使绑定到servlet的共享bean实例无效。

在这种情况下创建 SharedBean 会更好 在servlet中,将其作为参数传递给会话上下文并使用 bean中的 SessionContext 用于获取 SharedBean 实例。

由于评论而更新

注入的bean由容器管理。表示容器负责创建和销毁bean。如果创建bean的新实例,则引用(地址)或bean实例与servlet容器分离,并且不再由容器管理。因此,共享bean引用不适用于托管bean Bean1

由于评论而更新

问题的答案是,您在Servlet方法的 doGet 方法中创建的 SharedBean 实例未传递给servlet容器,因此不会可用于托管bean Bean1