In welcher Phase wird eine verwaltete Bean erstellt und welcher Konstruktor wird verwendet
-
21-12-2019 - |
Frage
Betrachten Sie ein Beispiel für eine JSF-basierte Web-App hello1
aus dem offiziellen Tutorial mit Zusatzkonstruktor in verwalteter Bean.Das folgende index.xhtml
facelet
<html lang="en"
xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://xmlns.jcp.org/jsf/html">
<h:head>
<title>Facelets Hello Greeting</title>
</h:head>
<h:body>
<h:form>
<h:graphicImage url="#{resource['images:duke.waving.gif']}"
alt="Duke waving his hand"/>
<h2>Hello hui, my name is Duke. What's yours?</h2>
<h:inputText id="username"
title="My name is: "
value="#{hello.name}"
required="true"
requiredMessage="Error: A name is required."
maxlength="25" />
<p></p>
<h:commandButton id="submit" value="Submit" action="response">
</h:commandButton>
<h:commandButton id="reset" value="Reset" type="reset">
</h:commandButton>
</h:form>
<div class="messagecolor">
<h:messages showSummary="true"
showDetail="false"
errorStyle="color: #d20005"
infoStyle="color: blue"/>
</div>
</h:body>
</html>
und modifizierte verwaltete Bohne Hello.java
package javaeetutorial.hello1;
import javax.enterprise.context.RequestScoped;
import javax.inject.Named;
@Named
@RequestScoped
public class Hello {
private String name;
public Hello() {
}
public Hello(String name){
this.name=name;
}
public String getName() {
return name;
}
public void setName(String user_name) {
this.name = user_name;
}
}
Es gibt zwei öffentliche Konstrukteure.Lassen Sie uns diese App auf dem Server bereitstellen und die erste Anfrage senden, geben Sie den Namen ein inputText
und klicken Sie auf submit
.Es gibt eine Postback-Anfrage nach submit
klicken.Daher haben wir, wie in tutroial geschrieben, die folgende Unterphase der Ausführungsphase:
- Die Anwendungsansicht wird erstellt oder wiederhergestellt.
- Die Werte der Anforderungsparameter werden angewendet.
- Konvertierungen und Validierungen werden für Komponentenwerte durchgeführt.
- Verwaltete Beans werden mit Komponentenwerten aktualisiert.
- Anwendungslogik wird aufgerufen.
In welcher Phase wird eine Instanz einer verwalteten Bean erstellt?
Welcher Konstruktor wird für diese Instanzerstellung aufgerufen und warum?Ich verstehe nicht, wie es von der beobachtet werden kann index.xhtml
Codes.
Lösung
In welcher Phase wird eine Instanz einer verwalteten Bean erstellt?
Niemand speziell.Es wird zum ersten Mal erstellt, wenn ein beliebiger EL-Ausdruck zum ersten Mal auf die verwaltete Bean verweisen muss, während die Bean-Instanz nicht in ihrem Gültigkeitsbereich vorhanden ist.Dies ist nicht von einem bestimmten Faces-Ereignis abhängig.Dies kann während der Wiederherstellungsphase der Ansicht (der ersten Phase) sein, aber dies kann auch während der Renderreaktionsphase (der letzten Phase) oder jeder anderen Phase dazwischen genauso gut sein.
Dies hängt alles davon ab, wie und wo die Bean im EL-Kontext referenziert wird über #{bean.xxx}
in der Ansicht (oder programmgesteuert im Modell).Sie sollten sich darüber im Allgemeinen keine Sorgen machen.JSF (speziell EL) wird es zumindest nicht früher als nötig erstellen, um die Ansicht ordnungsgemäß zu erstellen, zu verarbeiten oder zu rendern.
Welcher Konstruktor wird für diese Instanzerstellung aufgerufen und warum?
Der Standardkonstruktor natürlich.Weil die Javabeans-Spezifikation das sagt.Alle anderen Konstruktoren werden niemals von der von JSF / CDI verwalteten Bean-Einrichtung verwendet.
Selbst dann sollten Sie sich keine Sorgen um Konstrukteure machen.Sie sollten die Initialisierung besser in einem durchführen @PostConstruct
annotierte Methode statt in einem Konstruktor.Wenn die Bean nämlich von einem Bean-Management-Framework verwaltet wird, das Proxys wie CDI verwendet, kann der Standardkonstruktor häufiger als gewünscht aufgerufen werden.
Ich verstehe nicht, wie es aus dem Index beobachtet werden kann.xhtml-Code.
Setzen Sie einfach einen Haltepunkt in den Konstruktor, @PostConstruct
, oder eine beliebige relevante Getter / Setter-Methode und führen Sie das Projekt im Debug-Modus aus.Sobald der Haltepunkt erreicht ist, untersuchen Sie den Aufrufstapel.Die beteiligten Klassen und Methoden haben im Allgemeinen eher selbstdokumentierende Namen.Hier ist ein Beispiel, wie der Aufrufstapel aussehen kann, wenn Sie verwenden @Named
:
Daemon Thread [http-bio-8088-exec-6] (Suspended (entry into method <init> in TestBean))
owns: LocalCache$StrongEntry (id=503)
owns: SocketWrapper (id=504)
TestBean$Proxy$_$$_WeldClientProxy.<init>() line: not available [local variables unavailable]
NativeConstructorAccessorImpl.newInstance0(Constructor, Object[]) line: not available [native method]
NativeConstructorAccessorImpl.newInstance(Object[]) line: 57
DelegatingConstructorAccessorImpl.newInstance(Object[]) line: 45
Constructor.newInstance(Object...) line: 526
Class.newInstance() line: 374
NewInstanceAction.run() line: 33
AccessController.doPrivileged(PrivilegedExceptionAction<T>) line: not available [native method]
ClientProxyFactory(ProxyFactory).create(BeanInstance) line: 271
ClientProxyFactory.create(BeanInstance) line: 111
ClientProxyProvider.createClientProxy(Bean<T>, Set<Type>) line: 181
ClientProxyProvider.createClientProxy(Bean<T>) line: 171
ClientProxyProvider.access$100(ClientProxyProvider, Bean) line: 45
ClientProxyProvider$CreateClientProxy.load(Bean<Object>) line: 56
ClientProxyProvider$CreateClientProxy.load(Object) line: 52
LocalCache$LoadingValueReference.loadFuture(K, CacheLoader<? super K,V>) line: 3589
LocalCache$Segment.loadSync(K, int, LoadingValueReference<K,V>, CacheLoader<? super K,V>) line: 2374
LocalCache$Segment.lockedGetOrLoad(K, int, CacheLoader<? super K,V>) line: 2337
LocalCache$Segment.get(K, int, CacheLoader<? super K,V>) line: 2252
LocalCache.get(K, CacheLoader<? super K,V>) line: 3990
LocalCache.getOrLoad(K) line: 3994
LocalCache$LocalLoadingCache.get(K) line: 4878
LoadingCacheUtils.getCacheValue(LoadingCache<K,V>, K) line: 52
LoadingCacheUtils.getCastCacheValue(LoadingCache<K,V>, Object) line: 80
ClientProxyProvider.getClientProxy(Bean<T>) line: 187
WeldELResolver(AbstractWeldELResolver).lookup(BeanManagerImpl, ELContext, String) line: 110
WeldELResolver(AbstractWeldELResolver).getValue(ELContext, Object, Object) line: 91
WeldApplication$LazyBeanManagerIntegrationELResolver(ForwardingELResolver).getValue(ELContext, Object, Object) line: 49
CompositeELResolver.getValue(ELContext, Object, Object) line: 67
DemuxCompositeELResolver._getValue(int, ELResolver[], ELContext, Object, Object) line: 176
DemuxCompositeELResolver.getValue(ELContext, Object, Object) line: 203
AstIdentifier.getValue(EvaluationContext) line: 72
ValueExpressionImpl.getValue(ELContext) line: 185
WeldValueExpression.getValue(ELContext) line: 50
ELText$ELTextVariable.writeText(ResponseWriter, ELContext) line: 227
ELText$ELTextComposite.writeText(ResponseWriter, ELContext) line: 150
TextInstruction.write(FacesContext) line: 85
UIInstructions.encodeBegin(FacesContext) line: 82
UIInstructions(UILeaf).encodeAll(FacesContext) line: 207
HtmlBody(UIComponent).encodeAll(FacesContext) line: 1899
UIViewRoot(UIComponent).encodeAll(FacesContext) line: 1899
FaceletViewHandlingStrategy.renderView(FacesContext, UIViewRoot) line: 451
MultiViewHandler.renderView(FacesContext, UIViewRoot) line: 131
ConversationAwareViewHandler(ViewHandlerWrapper).renderView(FacesContext, UIViewRoot) line: 337
RenderResponsePhase.execute(FacesContext) line: 120
RenderResponsePhase(Phase).doPhase(FacesContext, Lifecycle, ListIterator<PhaseListener>) line: 101
LifecycleImpl.render(FacesContext) line: 219
FacesServlet.service(ServletRequest, ServletResponse) line: 647
...
Beginne unten (ich habe danach alle Zeilen entfernt FacesServlet.service
da diese im Allgemeinen irrelevant sind) und von unten nach oben lesen.Der RenderResponsePhase.execute
gibt an, dass es während der Renderantwortphase ausgeführt wird.Der TextInstruction.write
sagt, dass es beim Schreiben des Ergebnisses von EL in Vorlagentext wie folgt aufgetreten ist <p>#{bean.something}</p>
.Der Rest ist nur, wie die CDI-Implementierungsschweißung den Proxy findet und instanziiert und wie er wiederum die tatsächliche Bean-Referenz instanziiert.
Wenn es in einer anderen Phase passiert wäre, würden Sie stattdessen RenderResponsePhase.execute
habe zum Beispiel gesehen UpdateModelValuesPhase.execute
und so weiter.