web-dev-qa-db-de.com

Wie funktioniert das Attribut 'binding' in JSF? Wann und wie soll es angewendet werden?

Es gibt viele Materialien, die das value Attribut und das binding Attribut in JSF unterscheiden.

Mich interessiert, wie sich beide Ansätze voneinander unterscheiden. Gegeben:

public class User {
    private String name;
    private UICommand link;

    // Getters and setters omitted.
}
<h:form>
    <h:commandLink binding="#{user.link}" value="#{user.name}" />
</h:form>

Es ist ziemlich einfach, was passiert, wenn ein value -Attribut angegeben wird. Der Getter wird ausgeführt, um den Eigenschaftswert name der Bean User zurückzugeben. Der Wert wird in der HTML-Ausgabe ausgegeben.

Aber ich konnte nicht verstehen, wie binding funktioniert. Wie verwaltet der generierte HTML-Code eine Bindung mit der Eigenschaft link der Bean User?

Nachfolgend finden Sie den relevanten Teil der generierten Ausgabe nach manueller Verschönerung und Kommentierung (beachten Sie, dass die ID j_id_jsp_1847466274_1 wurde automatisch generiert und es gibt zwei versteckte Eingabe-Widgets. Ich verwende Suns JSF RI, Version 1.2.

<form action="/TestJSF/main.jsf" enctype="application/x-www-form-urlencoded"
    id="j_id_jsp_1847466274_1" method="post"  name="j_id_jsp_1847466274_1">
    <input name="j_id_jsp_1847466274_1" type="hidden" value="j_id_jsp_1847466274_1">
    <a href="#" onclick="...">Name</a>
    <input autocomplete="off" id="javax.faces.ViewState" name="javax.faces.ViewState"
        type="hidden" value="-908991273579182886:-7278326187282654551">
</form>

Wo ist das binding hier gespeichert?

71
John

Wie funktioniert es?

Wenn eine JSF-Ansicht (Facelets/JSP-Datei) erstellt/wiederhergestellt wird, wird ein JSF-Komponentenbaum erstellt. In diesem Moment, der View Build Time , werden alle binding Attribute ausgewertet ( zusammen mit id Attributen und Taghandlern wie JSTL ). Wenn die JSF-Komponente erstellt werden muss, bevor sie zum Komponentenbaum hinzugefügt wird, prüft JSF, ob das Attribut binding eine vorgefertigte Komponente (dh nichtnull) zurückgibt, und verwendet sie in diesem Fall . Wenn es nicht vorab erstellt wurde, erstellt JSF die Komponente automatisch "auf die übliche Weise" und ruft den Setter hinter dem Attribut binding mit der automatisch erstellten Komponenteninstanz als Argument auf.

In Effects wird eine Referenz der Komponenteninstanz im Komponentenbaum an eine Bereichsvariable gebunden. Diese Informationen sind in der generierten HTML-Darstellung der Komponente selbst in keiner Weise sichtbar. Diese Informationen sind in keiner Weise relevant für die generierte HTML-Ausgabe. Wenn das Formular gesendet und die Ansicht wiederhergestellt wird, wird der JSF-Komponentenbaum nur von Grund auf neu erstellt, und alle binding -Attribute werden wie oben beschrieben neu ausgewertet. Nach der Neuerstellung des Komponentenbaums stellt JSF den JSF-Ansichtsstatus im Komponentenbaum wieder her.

Komponenteninstanzen haben einen Anforderungsbereich!

Es ist wichtig zu wissen und zu verstehen, dass die konkreten Komponenteninstanzen effektiv einen Anforderungsbereich haben. Sie werden bei jeder Anforderung neu erstellt und ihre Eigenschaften werden während der Phase der Wiederherstellungsansicht mit Werten aus dem JSF-Ansichtsstatus gefüllt. Wenn Sie also die Komponente an eine Eigenschaft einer Backing-Bean binden, sollte die Backing-Bean absolut nicht in einem breiteren Bereich als dem Anforderungsbereich liegen. Siehe auch JSF 2.0 Spezifikation Kapitel 3.1.5:

3.1.5 Komponentenbindungen

...

Komponentenbindungen werden häufig in Verbindung mit JavaBeans verwendet, die über die Managed Bean Creation-Funktion dynamisch instanziiert werden (siehe Abschnitt 5.8.1 „VariableResolver und der Standard-VariableResolver“). Es wird dringend empfohlen, dass Anwendungsentwickler verwaltete Beans, auf die durch Komponentenbindungsausdrücke verwiesen wird, im Gültigkeitsbereich "request" platzieren. Dies liegt daran, dass sie in session oder platziert werden Der Anwendungsbereich erfordert Thread-Sicherheit, da UIComponent-Instanzen von der Ausführung in einem einzelnen Thread abhängen. Es gibt auch potenziell negative Auswirkungen auf die Speicherverwaltung, wenn eine Komponentenbindung in den Sitzungsbereich versetzt wird.

Andernfalls werden Komponenteninstanzen von mehreren Anforderungen gemeinsam genutzt, was möglicherweise zu " duplicate component ID " - Fehlern und "seltsamen" Verhalten führt, da in der Ansicht deklarierte Prüfer, Konverter und Listener erneut an die vorhandene Komponenteninstanz angehängt werden von früheren Anfragen. Die Symptome sind klar: Sie werden mehrmals ausgeführt, einmal mehr mit jeder Anforderung im selben Bereich, an den die Komponente gebunden wurde.

Unter hoher Last (d. H. Wenn mehrere unterschiedliche HTTP-Anforderungen (Threads) gleichzeitig auf dieselbe Komponenteninstanz zugreifen und diese manipulieren) kann es früher oder später zu einem Anwendungsabsturz kommen, z. Thread bei UIComponent.popComponentFromEL stecken geblieben oder Java-Threads bei 100% CPU-Auslastung mit RichFaces UIDataAdaptorBase und seiner internen HashMap oder sogar einige "seltsame" IndexOutOfBoundsException oder ConcurrentModificationException stammt direkt aus dem JSF-Implementierungsquellcode, während JSF damit beschäftigt ist, den Ansichtsstatus zu speichern oder wiederherzustellen (dh die Stapelverfolgung zeigt saveState() oder restoreState() Methoden und dergleichen an).

Die Verwendung von binding für eine Bean-Eigenschaft ist eine schlechte Praxis

Unabhängig davon ist die Verwendung von binding zum Binden einer gesamten Komponenteninstanz an eine Bean-Eigenschaft, auch bei einer Bean mit Anforderungsbereich, in JSF 2.x ein eher seltener Anwendungsfall und im Allgemeinen nicht die beste Vorgehensweise. Es zeigt einen Designgeruch an. Normalerweise deklarieren Sie Komponenten auf der Ansichtsseite und binden deren Laufzeitattribute wie value und möglicherweise andere wie styleClass, disabled, rendered usw. an die Norm Bohne Eigenschaften. Anschließend bearbeiten Sie einfach genau die gewünschte Bean-Eigenschaft, anstatt die gesamte Komponente zu erfassen und die dem Attribut zugeordnete Setter-Methode aufzurufen.

In Fällen, in denen eine Komponente auf der Grundlage eines statischen Modells "dynamisch erstellt" werden muss, ist es besser, Build-Time-Tags wie JSTL anzeigen zu verwenden, falls dies in einer Tag-Datei erforderlich ist. anstelle von createComponent(), new SomeComponent(), getChildren().add() und was nicht. Siehe auch Wie kann man das Snippet einer alten JSP in ein JSF-Äquivalent umgestalten?

Oder wenn eine Komponente basierend auf einem dynamischen Modell "dynamisch gerendert" werden muss, verwenden Sie einfach Iteratorkomponente (<ui:repeat>, <h:dataTable> Usw.). Siehe auch So fügen Sie JSF-Komponenten dynamisch hinz .

Composite Components ist eine ganz andere Geschichte. Es ist völlig legitim, Komponenten in einem <cc:implementation> An die Hintergrundkomponente zu binden (dh die mit <cc:interface componentType> Gekennzeichnete Komponente). Siehe auch ao Java.util.Date über zwei h: inputText-Felder aufteilen Darstellung von Stunde und Minute mit f: convertDateTime und So implementieren Sie eine dynamische Liste mit einer JSF 2.0 Composite Component?

Verwenden Sie binding nur im lokalen Bereich

Manchmal möchten Sie jedoch mehr über den Status einer anderen Komponente innerhalb einer bestimmten Komponente erfahren, als in Anwendungsfällen im Zusammenhang mit aktions-/wertabhängiger Validierung. Dafür kann das binding-Attribut verwendet werden, aber nicht in Kombination mit einer Bean-Eigenschaft. Sie können einfach einen im lokalen EL-Bereich eindeutigen Variablennamen im binding -Attribut wie folgt angeben binding="#{foo}" Und die Komponente befindet sich während des Renderns an einer anderen Stelle in derselben Ansicht wie UIComponent. Referenz verfügbar durch #{foo}. Hier sind einige verwandte Fragen, bei denen eine solche Lösung in der Antwort verwendet wurde:

Siehe auch:

121
BalusC

jede JSF-Komponente gibt sich selbst in HTML aus und hat die vollständige Kontrolle darüber, welches HTML sie erzeugt. Es gibt viele Tricks, die von JSF verwendet werden können. Welche dieser Tricks verwendet werden, hängt von der von Ihnen verwendeten JSF-Implementierung ab.

  • Stellen Sie sicher, dass jede from-Eingabe einen eindeutigen Namen hat, damit beim Zurücksenden des Formulars an den Komponentenbaum, der es gerendert hat, leicht festgestellt werden kann, wo jede Komponente ihr Wertformular lesen kann.
  • Die JSF-Komponente kann Javascript generieren, das an den Serer zurückgesendet wird. Das generierte Javascript weiß, wo auch jede Komponente gebunden ist, da es von der Komponente generiert wurde.
  • Für Dinge wie hlink können Sie verbindliche Informationen in die URL als Abfrageparameter oder als Teil der URL selbst oder als Matrx-Parameter einfügen. zum Beispiel.

    http:..../somelink?componentId=123 ermöglicht es jsf, in der Komponentenstruktur nachzuschauen, um festzustellen, ob auf den Link 123 geklickt wurde. oder es könnte e htp:..../jsf;LinkId=123

Die einfachste Möglichkeit, diese Frage zu beantworten, besteht darin, eine JSF-Seite mit nur einem Link zu erstellen und dann die von ihr erzeugte HTML-Ausgabe zu untersuchen. Auf diese Weise wissen Sie anhand der von Ihnen verwendeten JSF-Version genau, wie dies geschieht.

1
ams