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

TCM*_*TCM 8 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>
Run Code Online (Sandbox Code Playgroud)

这是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!");
    }

}
Run Code Online (Sandbox Code Playgroud)

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

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

Bal*_*usC 13

这个问题与你之前回答的问题有相同的理由:为什么@PostConstruct回调每次都会触发,即使bean是@ViewScoped?JSF.

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

这被报告为JSF问题1665JSF规范isssue 787,它针对JSF 2.2修复并移植回Mojarra 2.1.18.因此,只需升级到Mojarra 2.1.18即可.

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

也可以看看: