JSTL c:forEach导致@ViewScoped bean在每个请求上调用@PostConstruct

时间:2010-05-16 02:23:22

标签: java jsf jstl facelets

我再次看到@PostConstruct每次都在触发,即使没有使用绑定属性。请参阅此代码: -

<?xml version='1.0' encoding='UTF-8' ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
      xmlns:h="http://java.sun.com/jsf/html"
      xmlns:ui="http://java.sun.com/jsf/facelets"
      xmlns:c="http://java.sun.com/jsp/jstl/core">
    <h:head>
        <title>Facelet Title</title>
    </h:head>
    <h:body>
        <h:form>
            <c:forEach var="item" items="#{TestBean.listItems}">
                <h:outputText value="#{item}"/>
            </c:forEach>
            <h:commandButton value="Click" actionListener="#{TestBean.actionListener}"/>
        </h:form>
    </h:body>
</html>

这是JSF中最简单的bean: -

package managedBeans;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
import javax.annotation.PostConstruct;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.ViewScoped;

@ManagedBean(name="TestBean")
@ViewScoped
public class TestBean implements Serializable {

    private List<String> listItems;

    public List<String> getListItems() {
        return listItems;
    }

    public void setListItems(List<String> listItems) {
        this.listItems = listItems;
    }

    public TestBean() {

    }

    @PostConstruct
    public void init(){
        System.out.println("Post Construct fired!");
        listItems = new ArrayList<String>();
        listItems.add("Mango");
        listItems.add("Apple");
        listItems.add("Banana");
    }

    public void actionListener(){
        System.out.println("Action Listener fired!");
    }

}

您是否看到任何应该导致postconstruct回调每次触发的行为?我认为JSF 2.0非常不稳定。如果每次@ViewScoped服务的目的都必须触发PostConstruct。为什么不使用@RequestScoped?我以为我在申请中犯了一些错误。但是当我在JSF中创建这个最简单的时候,我仍然会遇到这个错误。我不了解JSF的范围吗?或者他们没有正确测试?此外,如果你删除c:forEach并用ui:repeat替换它,那么它可以正常工作。

等待回复以确认是否是错误或是否有意阻止程序员使用jstl?

1 个答案:

答案 0 :(得分:13)

此问题与您之前回答的问题具有相同的理由:Why does @PostConstruct callback fire every time even though bean is @ViewScoped? JSF

这确实是JSF2中的一个错误。这是一个鸡蛋问题。视图范围bean存储在JSF视图状态中。因此视图范围bean仅在还原视图阶段后可用。但是,JSTL标记在还原视图阶段运行,而视图范围Bean尚不可用。这会导致创建一个全新的视图范围的bean实例,然后由实际的视图范围bean替换,该实例存储在已恢复的JSF视图状态中。

报告为JSF issue 1665JSF spec isssue 787,这是针对JSF 2.2修复的,并在Mojarra 2.1.18中移植。因此,只需升级到Mojarra 2.1.18即可。

如果无法升级,那么最好的办法是在请求/会话/应用程序作用域上独占使用JSTL标记,或者寻找特定功能需求的替代方法。您可以将<c:forEach>替换为您已发现的<ui:repeat>

另见: