Ich habe eine Methode in einer Ansicht Scoped Bean mit der Annotation @PreDestroy
und eine weitere mit der Annotation @PostConstruct
.
Die Methode @PostConstruct
wird ordnungsgemäß aufgerufen, wenn ich zu der Seite navigiere, die diese Ansichtsbereichs-Bean verwendet.
Wenn ich jedoch zu einer neuen Seite (die dieses View-Scope-Bean nicht verwendet) durch <h:link/>
navigieren, wird die @PreDestroy
-Methode nie aufgerufen.
Ich spreche nicht über manuelle Änderung der URL oder das Ende der Sitzung , nur eines Navigationsfalls.
Was ich vermisse?
Vielen Dank im Voraus
Dies ist beabsichtigt. Es wird nur sofort gelöscht, wenn eine POST-Aktion zu einer Navigation führt, die kein Postback für dieselbe Ansicht ist (dh die Aktionsmethode gab nicht null
oder void
zurück, sondern eine vollwertige String
, auch wenn einfach leer).
Das <h:link>
generiert eine GET-Verknüpfung, die keine POST-Aktion aufruft. Da es nicht zuverlässig möglich ist, die Serverseite durch eine (XML-) HTTP-Anforderung zu benachrichtigen, wenn die Ansicht entladen wird, kann JSF nicht benachrichtigt werden, um die Ansichtsbereichs-Bean zu zerstören, die der Sicht zugeordnet ist. In einem solchen Fall wird die View-Scoped-Bean nur dann zerstört, wenn die Sitzung abläuft oder wenn die maximale Anzahl logischer Ansichten in der Sitzung überschritten wurde (der Standardwert ist 15) und die zugehörige Ansicht die erste in der Reihenfolge ist.
Wenn Sie wirklich die View-Scoped-Bean durch eine Navigaiton-Action destopen wollen, dann ist es am besten, wenn Sie stattdessen eine POST-Anfrage von <h:commandLink>
erstellen und eine Weiterleitung durch Rückgabe des Navigationsergebnisses ausgeben mit ?faces-redirect=true
-Parameter. Aber das ist schließlich nicht SEO-freundlich, da Bots keine POST-Links indexieren werden.
Ich würde mich schließlich nicht darum kümmern, dass die Ansicht noch in der Sitzung ist. Wenn Sie beabsichtigen, etwas aufzuräumen oder zu protokollieren, würde ich nach alternativen Wegen suchen, abhängig von den konkreten funktionalen Anforderungen.
In Theorie wäre es möglich durch HTML DOM onbeforeunload
event, aber dies ist ein Nicht-Standard-Ereignis und das Verhalten des Browsers ist nicht spezifiziert, was passiert, wenn Sie währenddessen eine Ajax-Anfrage senden Veranstaltung. Es wird manchmal ankommen, aber manchmal auch nicht. Aktualisieren : In üben wurde dies in OmniFaces @ViewScoped
seit OmniFaces 2.2 mit Hilfe von synchrone XHR und es funktioniert ziemlich gut in den wichtigsten Browsern. Seit Version 2.3 wird sogar der zugehörige JSF-Server-Seitenansichtszustand physisch zerstört.
Ich habe ein kleines NetBeans-Projekt vorbereitet, das zeigt, wann JSF2.2-CDI-kompatible @ViewScoped-Beans (javax.faces.view.ViewScoped) für die Garbage Collection in verschiedenen Navigationsfällen freigegeben werden (für Mojarra 2.2.9, Glassfish4, NetBeans8). 0.2, JDK1.7), verfügbar für hier herunterladen . Der Code wird hier weggelassen, bitte sehen Sie diesen Download.
Die behandelten Navigationsfälle und die Ergebnisse sind in diesem Bild zusammengefasst:
Um die @ViewScoped-Beans zu überwachen, verwenden Sie VisualVM gegen Glassfish (oder den integrierten NetBeans-Profiler auf dem Miniprojekt) und filtern Sie die Sampler-Speicher-Heap-Histogramm-Klassenansicht auf den Paketnamen 'webel.com.jsf'. Das folgende Bild zeigt eine absurde 66 Fälle von webel.com.jsf.Jsf22ViewBean nach ausgiebigem Experimentieren mit h: link, Browser-URL-GETs und Browser-RELOAD-GETs, bei denen keine Garbage Collection stattfindet (die Sie mit der Schaltfläche VisualVM Perform GC testen können):
Im Vergleich dazu navigieren Sie von der Datei index.xhtml (die die @ViewScoped-Bean einmal für eine einfache EL-Variablen liest) nach done.xhtml (die die Bean überhaupt nicht verwendet) mit h: commandButton und einer Aktionsmethode Ausdruck oder eine Aktionszeichenfolge bewirkt, dass die @ViewScoped-Bean für die Garbage Collection freigegeben wird (es gibt immer einen Verweis von WeldClientProxy auf eine @ViewScoped-Bean, und während Sie mit h: commandButton vor- und zurückwechseln, wird der WeldClientProxy von einer releasebaren Bean zu der nächste).