2010-02-16 32 views
5

這些天我正在學習JSF + Facelets。我有一個BackingBean和一個Facelet xHTML頁面。當我請求Facelet頁面(只有一次)時,backing-bean方法會被多次調用。爲什麼在請求facelet時多次調用BackingBean方法?

這可能是什麼原因?

我看不出任何特別的東西。提前致謝。

這裏是的facelet:

<?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:f="http://java.sun.com/jsf/core" xmlns:h="http://java.sun.com/jsf/html" xmlns:ui="http://java.sun.com/jsf/facelets"> 
<head> 
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /> 
<title>Insert title here</title> 
</head> 
<body> 
<ui:composition template="index.xhtml"> 
    <ui:define name="content"> 
     <h:form>Name: <h:inputText id="nameFilterPattern" value="#{kundenBackingBean.nameFilterPattern}" /><h:commandButton value="Suchen"/></h:form> 
     <h:dataTable var="kunde" value="#{kundenBackingBean.kunden}" rowClasses="rowHighlight, rowOrdinary"> 
      <h:column> 
       <f:facet name="header"> 
        <h:outputText value="Kundennr" /> 
       </f:facet> 
       <h:outputText value="#{kunde.kundenNr}"/> 
      </h:column> 
      <h:column> 
       <f:facet name="header"> 
        <h:outputText value="Name" /> 
       </f:facet> 
       <h:outputText value="#{kunde.name}"/> 
      </h:column> 
      <h:column> 
       <f:facet name="header"> 
        <h:outputText value="Vorname" /> 
       </f:facet> 
       <h:outputText value="#{kunde.vorname}"/> 
      </h:column> 
      <h:column> 
       <h:outputLink>Details</h:outputLink> 
      </h:column> 
     </h:dataTable> 
    </ui:define> 
</ui:composition> 
</body> 
</html> 

這裏是支持bean。該方法getKunden被多次調用:

@ManagedBean 
@SessionScoped 
public class KundenBackingBean extends AbstractBackingBean { 

    private String nameFilterPattern; 

    public List<Kunde> getKunden(){ 
     System.out.println("getKunden"); 
     return getApplication().getKunden(getNameFilterPattern()); 
    } 

    public String getNameFilterPattern() { 
     return nameFilterPattern; 
    } 

    public void setNameFilterPattern(String nameFilterPattern) { 
     System.out.println("Name filter: " + nameFilterPattern); 
     this.nameFilterPattern = nameFilterPattern; 
    } 

} 
+0

它總是被稱爲相同的次數? – volvox

+0

您是否使用IDE調試模式來驗證多次調用的方法,或者您在日誌中看到它? – Roman

+0

它似乎在第一次請求被稱爲8次,之後它被稱爲21次。我使用eclipse + glassfish並以調試模式啓動它。我只是將一個sysout插入到方法中並計算控制檯輸出。 – c0d3x

回答

8

一個bean的獲取者就在那裏從訪問從視圖方面的模型數據。他們可以被多次調用。通常是一次或兩次,但這可能會長達幾百次,尤其是在UIData組件中或value(如rendered,disabled等)以外的其他屬性中也會使用。這通常不會造成危害,因爲它只是一個簡單的方法調用,並且執行昂貴的數據加載邏輯或計算通常不會在getter中完成。預加載/初始化通常在bean構造函數和/或bean操作方法中完成。吸氣者其實應該只有返回的數據(如果需要還可以做延遲加載)。

如果getApplication().getKunden(getNameFilterPattern());是做了相當昂貴的任務,你應該將它移動到任何bean的構造函數,或豆@PostConstruct方法,或豆初始化塊,或豆操作方法,還是在吸氣介紹延遲加載模式。下面是它展示瞭如何做一個例子這一切:

public class Bean { 
    private String nameFilterPattern; 
    private List<Kunde> kunden; 

    // Load during bean construction. 
    public Bean() { 
     this.kunden = getApplication().getKunden(getNameFilterPattern()); 
    } 

    // OR load during @PostConstruct (will be invoked AFTER construction and resource injection. 
    @PostConstruct 
    public void init() { 
     this.kunden = getApplication().getKunden(getNameFilterPattern()); 
    } 

    // OR during bean initialization (this is invoked BEFORE construction and will apply to ALL constructors). 
    { 
     this.kunden = getApplication().getKunden(getNameFilterPattern()); 
    } 

    // OR during bean action method (invoked from h:commandLink/Button). 
    public String submit() { 
     this.kunden = getApplication().getKunden(getNameFilterPattern()); 
     return "navigationCaseOutcome"; 
    } 

    // OR using lazy loading pattern in getter method. 
    public List<Kunde> getKunden() { 
     if (this.kunden == null) 
      this.kunden = getApplication().getKunden(getNameFilterPattern()); 
     } 
     return this.kunden; 
    } 

在特定情況下,我認爲這是@PostConstruct(如果nameFilterPattern是從一個GET請求參數獲得的),或者只是豆操作方法(如果要從POST表單輸入字段獲得nameFilterPattern)是合適的。

要了解關於JSF生命週期的更多信息,您可能會發現這個self-practice article有用。

+0

不錯的答案,btw :) http://stackoverflow.com/questions/2090033/why-jsf-calls-getters-multiple-times – ewernli

+0

是的,這當然不是我第一次回答這樣的:)我已經回答了它至少有20次之前。不僅在這裏,而且在forums.sun.com等。 – BalusC

2

它可以從JSF lifecylce的不同phases被調用。我的賭注是階段RestoreView,然後RenderResponse - 我最近沒有使用JSF,所以我不記得這一點。

您可以緩存最新的過濾器模式和相應的客戶端。只有在過濾器發生變化時才重新加載客戶端。這樣,您可以解決此特定問題,並且避免在過濾器未更改時重新加載數據。

private String nameFilterPattern; 
private String lastNameFilterPatternLoaded; 
private List<Kunde> clients; 

public List<Kunde> getKunden(){ 
    System.out.println("getKunden"); 
    if(nameFilterPattern.equals(lastNameFilterPatternLoaded)) 
    { 
     clients = getApplication().getKunden(getNameFilterPattern()); 
     lastNameFilterPatternLoaded = nameFilterPattern 
    } 
    return clients; 
} 

或者你可以使用一個request豆(而不是session),並確保你每次請求加載數據只有一次。

+0

感謝您的回答。我改變了bean來請求範圍。行爲是一樣的。我如何確保每個請求只加載數據?正如您在facelet中看到的,該方法僅被引用一次。這是否可以與模板相關:ui:composition/ui:define? – c0d3x

+0

來自BalusC的您接受的答案涵蓋了所有內容。我想你不需要進一步的解釋。 – ewernli

相關問題