@PostConstruct为@ConversationScoped bean多次调用

时间:2011-05-28 12:22:52

标签: java java-ee-6 cdi jboss-weld seam-conversation

我有一个@ConversationScoped bean,带有一个start方法,如下所示:

@PostConstruct
public void start() {
    if (conversation.isTransient()) {
        conversation.begin();
        log.debug("conversation.getId(): " + conversation.getId());
    }
}

我的问题是,每次刷新页面时都会启动一个新会话,每次我对bean中的方法进行AJAX调用时,也会启动一个新的会话(这是我的主要问题)。

我真正希望发生的是让sam对话一直闲逛,直到我手动调用conversation.end()。我在这里缺少什么?

6 个答案:

答案 0 :(得分:5)

稍微偏离主题,但希望有价值:

我不是100%确定@PostConstruct是开始对话的合适场所。我宁愿使用像这样的面孔事件:

<f:metadata>
        <f:event type="javax.faces.event.PreRenderViewEvent"
                listener="#{myBean.init}" />
</f:metadata>

如果您确定不在JSF回发请求中,则启动对话。

public void init() {
       if (!FacesContext.getCurrentInstance().isPostback() && conversation.isTransient()) {
          conversation.begin();
       }
    }

如果您使用Seam 3,则更容易:

<f:metadata>
   <s:viewAction action="#{myBean.init}" if="#{conversation.transient}" />
</f:metadata>

答案 1 :(得分:3)

您是否检查过(AJAX)调用是否包含会话ID参数(cid)?

如果缺少,则每次通话都会开始新的对话。

答案 2 :(得分:3)

JSR-299内置对话的概念有点破碎。至少对于JSF应用程序。使用@PreRenderViewEvent基本上会降低此方法的所有好处,因为它会使每个 @ConversationScoped bean longRunning。

您可能会尝试使用Apache MyFaces CODI @ConversationScoped。 CODI是一个CDI扩展库,可以很好地与Apache OpenWebBeans和Weld一起使用。 它还提供@ViewScoped,@ ViewAccessScoped(一种自动对话)和@WindowScoped上下文。

更多信息:https://cwiki.apache.org/confluence/display/EXTCDI/Index

答案 3 :(得分:2)

一切都在文档中:

对话范围有效:

在任何JSF面部或非面部请求的所有标准生命周期阶段。

会话上下文提供对与特定会话相关联的状态的访问。每个JSF请求都有一个关联的对话。容器根据以下规则自动管理此关联:

任何JSF请求都只有一个关联的对话。     与JSF请求关联的对话在还原视图阶段开始时确定,并且在请求期间不会更改。

任何对话都处于以下两种状态之一:瞬态或长时间运行。

默认情况下,对话是暂时的     通过调用Conversation.begin()可以将短暂的会话标记为长时间运行     通过调用Conversation.end()

,可以将长时间运行的对话标记为瞬态

所有长时间运行的会话都有一个字符串值唯一标识符,当会话标记为长时间运行或由容器生成时,可由应用程序设置。

如果与当前JSF请求关联的对话在JSF请求结束时处于临时状态,则会被销毁,对话上下文也会被破坏。

如果与当前JSF请求关联的对话在JSF请求结束时处于长时间运行状态,则不会销毁该对话。相反,它可以根据以下规则传播到其他请求:

与呈现JSF视图的请求相关联的长时间运行的对话上下文会自动传播到源自该呈现页面的任何面部请求(JSF表单提交)。     与导致JSF重定向(由导航规则或JSF NavigationHandler产生的重定向)的请求相关联的长时间运行的对话上下文会自动传播到生成的非面部请求以及对同一URL的任何其他后续请求。这是通过使用名为cid的GET请求参数来完成的,该参数包含会话的唯一标识符。     通过使用包含会话的唯一标识符的名为cid的GET请求参数,可以将与请求相关联的长时间运行的会话传播到任何非面部请求。在这种情况下,应用程序必须管理此请求参数。

当没有会话传播到JSF请求时,该请求与新的临时会话相关联。所有长时间运行的会话都限定在特定的HTTP servlet会话中,并且可能不会跨越会话边界。在下列情况下,传播的长时间运行的会话无法恢复并与请求重新关联:

当HTTP servlet会话失效时,在servlet service()方法完成之后,将销毁在当前会话期间创建的所有长时间运行的会话上下文。     允许容器随意销毁与当前JSF请求相关联的任何长时间运行的对话,以节省资源。

作者:     Gavin King,Pete Muir

答案 4 :(得分:0)

恕我直言CDI对话被设计打破,struberg指出了一个有前景的替代方案。在我的应用程序中我遇到了同样的问题,目前我正在将它重构为CDI + CODI 1,它感觉很好。 @ConversationScoped解决了所有这些问题。在重构我的应用程序时,我可以使用@ViewAccessScoped解决许多令人讨厌的案例。感谢struberg指点我们!

答案 5 :(得分:0)

奇怪的是,如果你向Facelet添加一个事件监听器,即使它调用一个空方法,生成的源的表单动作也会有'cid'参数,因此,AJAX调用不会创建一个新的对话。如果没有事件监听器,表单操作中的'cid'就会丢失。

<f:metadata>
    <f:event listener="#{myBean.dummy}" type="preRenderView" />
</f:metadata>

MyBean.java

public void dummy() {}