多次调用 JSF Backing Bean 构造函数

Posted

技术标签:

【中文标题】多次调用 JSF Backing Bean 构造函数【英文标题】:JSF Backing Bean constructor called multiple times 【发布时间】:2011-06-17 02:48:51 【问题描述】:

我正在尝试 JSF 2.0(在过去几个月使用 ICEfaces 1.8 之后)并且我试图弄清楚为什么在 JSF 2.0 中我的支持 bean 构造函数被多次调用。

bean 应该在创建时被实例化一次,但是每当我单击 commandButton 时都会显示“Bean Initialized”文本,表明正在实例化一个新的 Bean 对象。

facelet 页面:

    <?xml version='1.0' encoding='UTF-8' ?>
<html xmlns="http://www.w3.org/1999/xhtml"
      xmlns:h="http://java.sun.com/jsf/html">

    <h:body>
        <div id="content">
            <h:form id="form">
                <h:commandButton value="Toggle" action="#bean.toggleShowMe"/>
            </h:form>


            <h:panelGrid rendered="#bean.showMe">
                <h:outputText value="Show me!"/>
            </h:panelGrid>
        </div>
    </h:body>
</html>

支持 bean:

@ManagedBean
@RequestScoped
public class Bean 
    private boolean showMe = false;

    public boolean isShowMe() 
        return showMe;
    

    public void setShowMe(boolean showMe) 
        this.showMe = showMe;
    

    public void toggleShowMe()
        System.out.println(showMe);
        if(showMe==true)
            showMe=false;
        else
            showMe=true;
        
    
    /** Creates a new instance of Bean */
    public Bean() 
        System.out.println("Bean Initialized");
    


就是这样。只是一个简单的测试。如果我使用 ICEfaces 2.0 并代替我使用的 panelGrid,也会出现同样的行为:

<ice:panelPopup visible="#bean.showMe">

如果能提供任何帮助,我将不胜感激。我不知道怎么解释。

更新:作为对 Aba Dov 的回应,我对 bean 进行了@SessionScoped,认为它不会在每次请求时调用构造函数并遇到相同的行为。我错过了什么?

【问题讨论】:

如果组件是会话范围的,它不会在每个会话中创建超过一次——因为这种行为被广泛使用,错误可能在您的代码中,而不是 JSF;你在使用正确包中的@SessionScoped 吗? (EE6中有两个)。 fdreger-我正在使用 javax.faces.bean.SessionScoped。我应该使用 javax.enterprise.context.SessionScoped 吗? 【参考方案1】:

您已声明要放置在请求范围内的 bean,并且每次都通过命令按钮触发一个新的 HTTP 请求。确实,每个请求都会创建 bean。

如果您希望 bean 的生命周期与视图本身一样长(就像 IceFaces 在幕后为所有 ajax 所做的那样),那么您需要声明 bean 视图的作用域(这是 JSF 2.0 中的新功能)。

@ManagedBean
@ViewScoped
public class Bean implements Serializable 

【讨论】:

感谢您的解释!有用。有什么建议可以让您了解最新的 JSF 2.0 吗?规范阅读量很大。 还要注意涉及 &lt;c:forEach ...&gt; 的代码和来自 bean 的列表。这将多次调用构造函数,即使 ViewScoped @Chris:另见***.com/questions/2842401/… @BalusC 我应该更详细地阅读该帖子,发现这很难。我确实有嵌套 ui:repeat (***.com/questions/3708490/…) 的问题。我真的很想看到 JSF 2.2 出来解决这些问题。 @Chris:&lt;ui:repeat&gt; 的状态管理在 Mojarra 中被严重破坏。使用 MyFaces 或以 UIData 风格提供它的第 3 方组件库(例如 &lt;t:dataList&gt;)。【参考方案2】:

在我的情况下,问题是我导入了“javax.faces.bean.ViewScoped”而不是导入“javax.faces.view.ViewScoped”。

希望它可以帮助某人。

【讨论】:

如***.com/questions/5541813/…中提到的【参考方案3】:

每次有来自页面的请求时都会调用 bean。

当您单击&lt;h:commandButton&gt; 时,表单已提交并向服务器发送请求

为了防止它,您可以使用&lt;t:saveState&gt;&lt;a4j:keepAlive&gt; 标记。

例如&lt;a4j:keepAlive beanName="YourBean" /&gt;

这些标签将 bean 实例存储在组件树中。

还要确保您的班级implements Serializable。所以可以序列化

希望对你有帮助

【讨论】:

在 JSF 2 中,viewscope 执行 keepAlive 或 saveState 的工作【参考方案4】:

bean 应该在 ViewScoped 中。

【讨论】:

如果您不需要将数据保存这么长时间怎么办.. viewScoped 可以工作但不是免费的,它会消耗您服务器上的内存,为什么您需要将不必要的数据保存这么长时间?由于 bean 已经请求了数据,因此将数据保留在视图范围内有什么意义,以及为什么 JSF 需要在按下 commmandButton 时在视图中创建所有托管 bean,为什么不只是actionListener bean 被实例化了?

以上是关于多次调用 JSF Backing Bean 构造函数的主要内容,如果未能解决你的问题,请参考以下文章

使用 URL 参数的 JSF 托管 Bean 方法调用

JSF 2.2 ViewScoped Bean 被多次创建

@ViewScoped JSF bean 被多次初始化

在JSF托管bean的构造函数中访问会话bean数据

从 Backing Bean 显示 Primefaces confirmDialog

读取 Backing Bean 中的隐藏值时为空值