JSF后台Bean构造函数被多次调用

5

我正在尝试使用JSF 2.0(之前使用ICEfaces 1.8几个月),并且我正在努力弄清楚为什么在JSF 2.0中我的后备bean构造函数会被多次调用。

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

面部页面:

    <?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吗? - TheDream34
4个回答

6

您已经声明了bean放置在请求范围内,并且每次通过命令按钮触发新的HTTP请求。实际上,bean将在每个请求时创建。

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

@ManagedBean
@ViewScoped
public class Bean implements Serializable {}

谢谢解释!它有效。有没有建议一个好的地方来了解新的JSF 2.0?规范是相当沉重的阅读材料。 - TheDream34
还要注意涉及<c:forEach ...>和来自bean的列表的代码。即使在ViewScoped下,这将多次调用构造函数。 - Christophe Roussy
@Chris:另请参阅https://dev59.com/003Sa4cB1Zd3GeqPydAo#2842424。 - BalusC
@BalusC 我应该更仔细地阅读那篇文章,但我是通过困难的方式发现这个问题的。我在嵌套的ui:repeat中遇到了问题(https://dev59.com/vFDTa4cB1Zd3GeqPJXUD)。我真的希望JSF 2.2能够解决这些问题。 - Christophe Roussy
1
@Chris:Mojarra中的<ui:repeat>状态管理严重失效。请使用MyFaces或第三方组件库,以UIData风格提供它(例如<t:dataList>)。 - BalusC

2
在我的情况下,问题是我导入了"javax.faces.bean.ViewScoped"而不是导入"javax.faces.view.ViewScoped"。
希望这能帮助到某些人。

1
如 https://dev59.com/F2035IYBdhLWcg3wPNdk 中所述。 - Kukeltje

0

每当页面发出请求时,就会调用该bean。

当您单击<h:commandButton>时,表单将被提交并向服务器发送请求。

为了防止这种情况,您可以使用<t:saveState><a4j:keepAlive>标签来保存您的bean。

例如:<a4j:keepAlive beanName="YourBean" />

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

还要确保您的类implements Serializable,以便它可以被序列化。

希望这可以帮助您。


在JSF 2中,视图作用域(viewscope)负责保持活动状态或保存状态的工作。 - Christophe Roussy

0

这个Bean应该在ViewScoped中。


如果您不需要长时间保留数据,那该怎么办?viewScoped 可以使用,但并非免费,它会消耗服务器上的内存,为什么要保留不必要的数据这么久呢?由于 bean 已经请求了数据,因此数据已经与视图一起存在,将数据保留在视图范围内有什么意义?为什么 JSF 需要在按下 commandButton 时触发所有托管 bean 的创建,而不是只实例化 actionListener bean 呢? - Rajat Gupta

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接