为什么JSF多次调用getter [英] Why JSF calls getters multiple times

查看:110
本文介绍了为什么JSF多次调用getter的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

比方说,我指定了一个outputText组件,如下所示:

Let's say I specify an outputText component like this:

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

如果在调用someProperty的getter并加载页面时打印日志消息,则很容易注意到每个请求多次调用getter(在我的情况下是两次或三次) ):

If I print a log message when the getter for someProperty is called and load the page, it is trivial to notice that the getter is being called more than once per request (twice or three times is what happened in my case):

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的值计算起来很昂贵,则可能是一个问题.

If the value of someProperty is expensive to calculate, this can potentially be a problem.

我在Google上搜索了一下,发现这是一个已知问题.一种解决方法是包括检查并查看它是否已经计算:

I googled a bit and figured this is a known issue. One workaround was to include a check and see if it had already been calculated:

private String someProperty;

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

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

The main problem with this is that you get loads of boilerplate code, not to mention private variables that you might not need.

此方法有哪些替代方案?没有太多不必要的代码,有没有办法实现这一目标?有没有办法阻止JSF以这种方式运行?

What are the alternatives to this approach? Is there a way to achieve this without so much unnecessary code? Is there a way to stop JSF from behaving in this way?

感谢您的输入!

推荐答案

这是由延迟表达式#{}的性质引起的(请注意,传统"标准表达式${}在使用Facelets而不是Facelets时表现完全相同) JSP).不会立即评估延迟的表达式,而是将其创建为

This is caused by the nature of deferred expressions #{} (note that "legacy" standard expressions ${} behave exactly the same when Facelets is used instead of JSP). The deferred expression is not immediately evaluated, but created as a ValueExpression object and the getter method behind the expression is executed everytime when the code calls ValueExpression#getValue().

通常,每个JSF请求-响应周期将调用一次或两次,具体取决于组件是输入组件还是输出组件(

This will normally be invoked one or two times per JSF request-response cycle, depending on whether the component is an input or output component (learn it here). However, this count can get up (much) higher when used in iterating JSF components (such as <h:dataTable> and <ui:repeat>), or here and there in a boolean expression like the rendered attribute. JSF (specifically, EL) won't cache the evaluated result of the EL expression at all as it may return different values on each call (for example, when it's dependent on the currently iterated datatable row).

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

Evaluating an EL expression and invoking a getter method is a very cheap operation, so you should generally not worry about this at all. However, the story changes when you're performing expensive DB/business logic in the getter method for some reason. This would be re-executed everytime!

Getter方法,使其仅返回已经准备好的属性,仅此而已. .com/technetwork/java/javase/documentation/spec-136004.html"rel =" nofollow noreferrer> Javabeans规范.他们根本不应该执行任何昂贵的DB/业务逻辑.为此,应使用bean的@PostConstruct和/或(动作)侦听器方法.在基于请求的JSF生命周期的某个时刻,它们仅执行一次,这正是您想要的.

Getter methods in JSF backing beans should be designed that way that they solely return the already-prepared property and nothing more, exactly as per the Javabeans specification. They should not do any expensive DB/business logic at all. For that the bean's @PostConstruct and/or (action)listener methods should be used. They are executed only once at some point of request-based JSF lifecycle and that's exactly what you want.

以下是预置/加载属性的所有 right 不同方式的摘要.

Here is a summary of all different right ways to preset/load a property.

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;
    }

}

请注意,您不应该不要使用作业的bean的构造函数或初始化块,因为如果您使用的是使用代理(例如CDI)的bean管理框架,则可能会多次调用它.

Note that you should not use bean's constructor or initialization block for the job because it may be invoked multiple times if you're using a bean management framework which uses proxies, such as CDI.

如果由于某些限制性设计要求,对于您而言确实没有其他方法,则应在getter方法内引入延迟加载. IE.如果该属性为null,则将其加载并分配给该属性,否则返回它.

If there are for you really no other ways, due to some restrictive design requirements, then you should introduce lazy loading inside the getter method. I.e. if the property is null, then load and assign it to the property, else return it.

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

        return someProperty;
    }

这样,就不必在每个getter调用中不必要地执行昂贵的DB/业务逻辑.

This way the expensive DB/business logic won't unnecessarily be executed on every single getter call.

  • Why is the getter called so many times by the rendered attribute?
  • Invoke JSF managed bean action on page load
  • How and when should I load the model from database for h:dataTable
  • How to populate options of h:selectOneMenu from database?
  • Display dynamic image from database with p:graphicImage and StreamedContent
  • Defining and reusing an EL variable in JSF page
  • Measure the render time of a JSF view after a server request

这篇关于为什么JSF多次调用getter的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆