当在 JSF 中处理一个表单时,它是否全部发生在一个线程中?

When a form is handled in JSF, does it all happen in one thread?

说我有这段代码

        <p:dataTable styleClass="scheduleTable" value="#{todaySchedule.hours}" var="hour">
            <p:column headerText="Hour" styleClass="hourColumn" >
                #{hour.time}
            </p:column>
        </p:dataTable>

并且在名为 todaySchedule 的 class 中,有一个方法

public List<Hour> getHours() {
        final List<Hour> hours = IntStream.range(0, Hour.TIME.values().length)
                                          .mapToObj($ -> new Hour()).collect(Collectors.toList());
        for (int i = 0; i < 5; i++) {
             hours.get(i).setHour(1);
        }
        return hours;
}

现在是时间 class

public class Hour {
    private int time;

    public int getTime() {
        return time;
    }

    public void setTime(int time) {
        this.time = time;
    }
}

现在,我不确定 JSF 在幕后做了什么来使这个动态 dataTable 数据迭代通过小时列表成为可能,但我假设如果这一切都发生在一个线程中,那就没问题了。但是,如果在幕后,getHours 在实际生成列的另一个线程中使用并看到 Hour 处于错误状态怎么办?如果 getHours() 方法是

,则可以避免这种情况
public List<Hour> getHours() {
        final List<Hour> hours = new ArrayList<>();
        for (int i = 0; i < 5; i++) {
            hours.add(new Hour(i + ""));
        }
        return hours;
}

with the corresponding Hour class being

public class Hour {
    private final int time;

    public Hour(int time) {
         this.time = time;
    }

    public int getTime() {
         return time;
    }
}

但是,我的问题是,如果不更改为后一种设计,在发布此 Hour 实例时,由于 Java 中的可见性问题,使用基本动态 JSF dataTable 呈现时是否会出现问题?

JSF 运行s 在 Servlet API 之上,它在一个线程中处理一个请求,因此除非您自己引入更多线程,否则您可能希望您的代码 运行 在一个单线程。

另一方面,您应该了解 JSF 生命周期的基础知识以及如何访问 bean 属性,如果您不了解这可能会给您带来很多麻烦。

例如,如果您的 Java 代码保持不变,则向您的 JSF 添加对 todaySchedule.hours 的另一个引用会导致 getter 被调用两次,从而生成两次内容.这很快就会变得非常混乱,所以做一些 "caching" 是一件好事。我个人使用这种方法:

private List<Hour> hours = null;

private void initHours() {
    this.hours = new LinkedList<>();
    // Fill hours here
}

public List<Hour> getHours() {
    if (this.hours == null) {
        initHours();
    }
    return this.hours;
}

尽管在 JSF 生命周期的哪个阶段执行此操作,但您必须小心。例如,如果您在表单处理方法中更改影响列表生成的数据,则列表可能已经 "cached" 来自恢复视图阶段,并且在呈现视图阶段开始时不会反映更改。在这种情况下,您应该注意缓存并在需要重新加载时清除列表。

public void saveHours() {
    // Save the data, do whatever you need to do

    // This will ensure re-initializing the list on the next call
    this.hours = null;
}