为什么 JSF 多次调用 getter

2023-12-10

假设我指定了一个如下所示的 outputText 组件:

<h:outputText value="#{ManagedBean.someProperty}"/>

如果我在 getter 时打印一条日志消息someProperty被调用并加载页面,很容易注意到每个请求多次调用 getter(在我的例子中发生了两次或三次):

DEBUG 2010-01-18 23:31:40,104 (ManagedBean.java:13) - Getting some property
DEBUG 2010-01-18 23:31:40,104 (ManagedBean.java:13) - Getting some property

如果值someProperty计算成本昂贵,这可能是一个问题。

我用谷歌搜索了一下,发现这是一个已知问题。一种解决方法是进行检查并查看是否已经计算过:

private String someProperty;

public String getSomeProperty() {
    if (this.someProperty == null) {
        this.someProperty = this.calculatePropertyValue();
    }
    return this.someProperty;
}

这样做的主要问题是您会获得大量样板代码,更不用说您可能不需要的私有变量了。

这种方法有哪些替代方案?有没有一种方法可以实现这一目标,而无需那么多不必要的代码?有没有办法阻止 JSF 出现这种行为?

感谢您的输入!


这是由延迟表达式的性质引起的#{}(请注意“遗留”标准表达式${}当使用 Facelets 而不是 JSP 时,其行为完全相同)。延迟表达式不是立即地评估,但创建为ValueExpression每次代码调用时都会执行对象和表达式后面的 getter 方法ValueExpression#getValue().

通常,每个 JSF 请求-响应周期都会调用该组件一次或两次,具体取决于该组件是输入组件还是输出组件(在这里学习)。然而,当用于迭代 JSF 组件(例如<h:dataTable> and <ui:repeat>),或者到处都是布尔表达式,例如rendered属性。 JSF(特别是 EL)根本不会缓存 EL 表达式的计算结果,因为它may每次调用时返回不同的值(例如,当它依赖于当前迭代的数据表行时)。

计算 EL 表达式并调用 getter 方法是一个非常便宜的操作,因此您通常根本不用担心这一点。然而,当您出于某种原因在 getter 方法中执行昂贵的数据库/业务逻辑时,情况就会发生变化。每次都会重新执行!

JSF 支持 bean 中的 Getter 方法应该这样设计:return已经准备好的财产,仅此而已,完全按照Javabean 规范。他们根本不应该执行任何昂贵的数据库/业务逻辑。为此,豆子的@PostConstruct和/或(动作)监听器方法应该被使用。他们被处决只有一次在基于请求的 JSF 生命周期的某个时刻,这正是您想要的。

这是所有不同的总结right预设/加载属性的方法。

public class Bean {

    private SomeObject someProperty;

    @PostConstruct
    public void init() {
        // In @PostConstruct (will be invoked immediately after construction and dependency/property injection).
        someProperty = loadSomeProperty();
    }

    public void onload() {
        // Or in GET action method (e.g. <f:viewAction action>).
        someProperty = loadSomeProperty();
    }           

    public void preRender(ComponentSystemEvent event) {
        // Or in some SystemEvent method (e.g. <f:event type="preRenderView">).
        someProperty = loadSomeProperty();
    }           

    public void change(ValueChangeEvent event) {
        // Or in some FacesEvent method (e.g. <h:inputXxx valueChangeListener>).
        someProperty = loadSomeProperty();
    }

    public void ajaxListener(AjaxBehaviorEvent event) {
        // Or in some BehaviorEvent method (e.g. <f:ajax listener>).
        someProperty = loadSomeProperty();
    }

    public void actionListener(ActionEvent event) {
        // Or in some ActionEvent method (e.g. <h:commandXxx actionListener>).
        someProperty = loadSomeProperty();
    }

    public String submit() {
        // Or in POST action method (e.g. <h:commandXxx action>).
        someProperty = loadSomeProperty();
        return "outcome";
    }

    public SomeObject getSomeProperty() {
        // Just keep getter untouched. It isn't intented to do business logic!
        return someProperty;
    }

}

请注意,您应该not使用 bean 的构造函数或初始化块来完成作业,因为如果您使用使用代理的 bean 管理框架(例如 CDI),它可能会被多次调用。

如果由于某些限制性的设计要求,您确实没有其他方法,那么您应该在 getter 方法中引入延迟加载。 IE。如果该房产是null,然后加载并将其分配给属性,否则返回它。

    public SomeObject getSomeProperty() {
        // If there are really no other ways, introduce lazy loading.
        if (someProperty == null) {
            someProperty = loadSomeProperty();
        }

        return someProperty;
    }

这样,昂贵的数据库/业务逻辑就不会在每个 getter 调用上不必要地执行。

也可以看看:

  • 为什么渲染属性会多次调用 getter?
  • 在页面加载时调用 JSF 托管 Bean 操作
  • 我应该如何以及何时从 h:dataTable 的数据库加载模型
  • 如何从数据库填充 h:selectOneMenu 的选项?
  • 使用 p:graphicImage 和 StreamedContent 显示数据库中的动态图像
  • 在 JSF 页面中定义和重用 EL 变量
  • 测量服务器请求后 JSF 视图的呈现时间
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

为什么 JSF 多次调用 getter 的相关文章

随机推荐