2011-08-25 7 views
11

Sto riscontrando un problema di prestazioni con le richieste ajax JSF/RichFaces/Facelets e da quello che posso dire perché l'intero albero dei componenti viene ricostruito su ogni richiesta Ajax. Ciò accade anche se utilizzo ajaxSingle = true, avvolgo sezioni in a4j: region, dichiaro una singola sezione per il rerendering o nessuna. La nostra pagina è una pagina dinamica con molti livelli nidificati. La pagina può contenere circa 800-900 campi (inputText, rich calendars, selectOneMenus, ecc.). Il tempo di caricamento iniziale è un problema, ma capisco quel problema, è un sacco di campi. Una volta ottenuto il tempo di generazione/rendering iniziale, abbiamo progettato tutte le altre azioni per essere ajax e restituire solo ciò che è necessario. Dai registri di debug facelets vedo messaggi come questo su qualsiasi chiamata AJAX:Visualizzazione JSF durante la ricostruzione di ogni richiesta Ajax

2011-08-24 22:19:03,054 DEBUG [facelets.viewhandler] (http-0.0.0.0-8080-2) Took 
24445ms to build view: /oconsole/appfile.xhtml 
2011-08-24 22:19:09,377 DEBUG [facelets.viewhandler] (http-0.0.0.0-8080-2) Took 
6323ms to render view: /oconsole/appfile.xhtml 

non sono sicuro se qualcosa che stiamo facendo sta causando la ricostruzione dell'intero albero componente o facelets sta determinando questo bisogno richiesto per alcune motivo (cache obsoleta?). Ecco il nostro stack: JBoss 5.1 JSF 1.2 RichFaces. 3.3.3.Final Facelets 1.1.15 Seam 2.1.2

Ho provato ad aggiungere alcuni parametri di contesto per vedere se avrebbero aiutare, ma non ha fatto nulla: facelets.BUILD_BEFORE_RESTORE = false facelets.REFRESH_PERIOD = - 1 o 5 (come in 5min)

C'è comunque un modo per dire se le nostre viste vengono memorizzate correttamente nella cache? Noi non consideriamo un metodo di salvataggio dello stato, quindi credo che sia predefinito sul lato server. Tutte le nostre richieste avvengono all'interno di conversazioni a lungo termine. Non ero sicuro che questo abbia un valore, dal momento che pensavo che le visualizzazioni venissero memorizzate nella cache a livello di sessione? Qualsiasi aiuto sarebbe molto apprezzato, grazie.

Aggiornamento dopo più di debug:

L'AjaxViewHandler (che ha una variabile membro della FaceletsViewHandler) ha developmentMode = true set. Non sono sicuro che ciò stia causando il fatto che facelets non memorizzi alcuna vista in modo tale che eventuali modifiche vengano aggiornate durante i cicli di sviluppo ... ?? È stato molto difficile trovare informazioni su facelets/JSF nella cache dei punti di vista e sul comportamento e sul controllo di ciò. Inoltre, quando aggiungo param config:

<context-param> 
<param-name>facelets.DEVELOPMENT</param-name> 
<param-value>false</param-value> 
</context-param> 

Questo non ha preso! Nel debugger vedo ancora il vero set. Dato che abbiamo molte sottoview, ho provato anche com.sun.faces.numberOfLogicalViews e com.sun.faces.numberOfViewsInSession a 1000 su da 15 (impostazione predefinita) e ciò non ha avuto alcun effetto.

Ho anche provato a passare al salvataggio dello stato lato client senza alcuna fortuna. A corto di idee .... spero che qualcuno possa aiutare ....

Sembra Seam 2.1 auto-inizializza RichFaces e non sono sicuro se questo ha qualcosa a che fare con esso .....

+0

So che questa è una vecchia domanda ... ma con così tanti campi, puoi prendere in considerazione di fare questo: http://industrieit.com/blog/2011/11/stateless-jsf-high-performance-zero-per -request-memory-overhead/ –

risposta

5

Come per qualsiasi problema di prestazioni, un profiler sarebbe di grande aiuto nell'individuare i colli di bottiglia. (Sì, lo sai che è la fase restore_view, ma non dove è nella fase restore_view).

Detto questo, la fase di visualizzazione ripristino ripristina effettivamente l'intera vista, non solo le parti che verranno elaborate o renderizzate. Citando il RichFaces taglib documentation: processo

: Id [ 's] (in formato di chiamata UIComponent.findComponent()) dei componenti, trasformato nelle fasi 2-5 in caso di AjaxRequest causati da questo componente.Può essere id singolo, elenco separato da virgole di Id, o EL espressione con matrice o accumulazione

RESTORE_VIEW è fase 1. Inoltre:

rerender: Id [ 's] (in formato di chiamata UIComponent.findComponent()) di componenti, resi in caso di AjaxRequest causato da questo componente. Può essere Single, elenco separato da virgole di ID, o EL espressione con matrice o un insieme

Inoltre, non sono sicuro che UIComponent.findComponent() viene implementato utilizzando un datastructure più adatto di un albero componente. (Trovare qualcosa nell'albero dei componenti si ridurrebbe alla ricerca lineare ...).

Ho osservato effetti simili con JSF 2.0 (Mojarra). La mia conclusione è stata che le viste non devono contenere più di una dozzina di UIComponents, indipendentemente dal fatto che siano renderizzati. (In modo diverso, AJAX non è adatto per la navigazione della pagina.) Ci impegniamo a mantenere le visualizzazioni di piccole dimensioni includendo solo i componenti attualmente visibili nella vista, e cambiamo le visualizzazioni se devono apparire molti nuovi componenti. Cioè, invece di una vista con 10 schede con 30 componenti ciascuna, avremmo 10 viste, ciascuna contenente solo il contenuto di una singola scheda. Uno svantaggio di questo approccio è che i componenti vengono eliminati quando si passa da una scheda all'altra, causando la perdita di qualsiasi stato non contenuto nei backing bean.

Non ritengo che questa sia una buona soluzione. Ahimè, è stato il migliore che ho trovato guardando questo un paio di settimane fa. Sarei felice di mostrarne anche uno migliore.

Modifica Quando dico di ripristino, voglio dire ViewHandler.restoreView(), che chiama sia per una richiesta GET iniziale e un postback. Non è corretto dire che restoreView semplicemente riutilizzerebbe una vista esistente così com'è. Per esempio, il JSF 2.0 mandati spec nella sezione 7.6.2.7:]

Il metodo restoreView() deve soddisfare le seguenti responsabilità:

Tutte le implementazioni devono:

  • Se non viewId hanno potuto essere identificati , restituire null.
  • chiamano il metodo degli associati StateManagerrestoreView(), passando l'istanza FacesContext per la richiesta corrente e calcolata viewId, e riportare il restituito UIViewRoot, che può essere null.

ed in sezione 7.7.2:

implementazioni JSF supporta due meccanismi principali per stato di risparmio, in base al valore del parametro di inizializzazione javax.faces.STATE_SAVING_METHOD (vedere Sezione 11.1. 3 "Configurazione dell'applicazione Parametri"). I valori possibili per questo parametro forniscono un'indicazione generale dell'approccio da utilizzare, consentendo implementazioni JSF di innovare sui dettagli tecnici:

  • cliente - [...]
  • server
  • - Causa lo stato salvato sul server tra le richieste. Le implementazioni che desiderano abilitare lo stato salvato in un'istanza contenitore diversa devono tenere presente questo quando implementano la loro strategia di salvataggio dello stato laterale del server . L'implementazione predefinita Serializza la vista in entrambe le modalità client e server. Nella modalità server , questa vista serializzata viene archiviata nella sessione e una chiave univoca per recuperare la vista viene inviata al client . Memorizzando la vista serializzata nella sessione, il failover può avvenire utilizzando i soliti meccanismi forniti dal contenitore .

In altre parole, il supporto AJAX aggiunto JSF (sia quella aggiunta da RichFaces 3 a JSF 1.2, e quello incorporato in JSF 2.0) mira a ridurre il consumo di larghezza di banda di rete, non assistente assorbita CPU.

+0

Meriton grazie per il vostro contributo, sono confuso però. Si suppone che l'intero punto di Ajax sia in grado di eseguire un rerender parziale molto veloce, dietro le quinte. Ho pensato a JSF/Facelets/Richfaces memorizza/memorizza le visualizzazioni e riutilizza la struttura dei componenti, se possibile. Quando dici "ripristina" sopra, penso che dobbiamo essere chiari sul ripristino dalla cache o dalla ricostruzione. Sono principalmente preoccupato di aver specificato tramite i tag RichFaces tutte le informazioni che mi servono solo un sottogruppo molto piccolo della pagina per essere aggiornato su questa azione, perché dovrebbe costruire l'intero albero? –

+0

Ho ampliato la mia risposta per rispondere alle vostre domande. – meriton

+0

Grazie ancora Meriton per il tuo follow-up. Sembra che la nostra unica opzione sia quella di modificare le prestazioni della nostra logica che costruisce queste viste dinamiche e di romperle in base alla progettazione. Questo è molto deludente dal punto di vista del design JSF/Facelets, per essere così inefficiente quando non è necessario, non lo capisco. –

1

Dalla mia analisi il problema è causato dall'implementazione di facelet. Sulla base di debugger le seguenti linee di FaceletViewHandler classe, provoca ricostruzione dell'albero su ogni richiesta (anche AJAX) (buildBeforeRestore è falso, così buildView metodo viene richiamato):

 // build view - but not if we're in "buildBeforeRestore" 
     // land and we've already got a populated view. Note 
     // that this optimizations breaks if there's a "c:if" in 
     // the page that toggles as a result of request processing - 
     // should that be handled? Or 
     // is this optimization simply so minor that it should just 
     // be trimmed altogether? 
     if (!this.buildBeforeRestore 
       || viewToRender.getChildren().isEmpty()) { 
      this.buildView(context, viewToRender); 
     } 

Così nella mia mente per risolvere il problema di albero ricostruire su ogni richiesta è di approfondire l'implementazione di Facelets e fare la reimplementazione ... Preferirei piuttosto ristrutturare la vista e minimizzare il numero di componenti, quindi il tempo di costruzione dell'albero è basso.