En qué fase se construye el bean gestionado y qué constructor se utiliza
-
21-12-2019 - |
Pregunta
Considere un ejemplo de aplicación web basada en JSF hello1
del tutorial oficial con constructor adicional en bean administrado.El seguimiento index.xhtml
faceta
<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>
y frijol administrado modificado 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;
}
}
Hay dos constructores públicos.Implementemos esta aplicación en el servidor y enviemos la solicitud inicial, escriba el nombre en inputText
y haga clic submit
.Hay una solicitud de devolución de datos después submit
hacer clic.Por lo tanto, como está escrito en tutroial, tenemos la siguiente subfase de la fase de ejecución:
- La vista de la aplicación se construye o restaura.
- Se aplican los valores del parámetro de solicitud.
- Las conversiones y validaciones se realizan para los valores de los componentes.
- Los beans administrados se actualizan con los valores de los componentes.
- Se invoca la lógica de la aplicación.
¿En qué fase se creará la instancia del bean administrado?
¿Qué constructor se invocará para la creación de esta instancia y por qué?No entiendo como se puede observar desde el index.xhtml
código.
Solución
¿En qué fase se creará la instancia del bean administrado?
Nadie específicamente.Se construye por primera vez cuando una expresión EL arbitraria necesita hacer referencia al bean administrado por primera vez mientras la instancia del bean no está presente en su alcance.Esto no depende de ningún evento de caras en particular.Esto puede ser durante la fase de vista de restauración (la primera fase), pero también puede ser igual de bueno durante la fase de respuesta de renderizado (la última fase) o cualquier otra fase intermedia.
Todo esto depende de cómo y dónde se hace referencia al bean en el contexto EL a través de #{bean.xxx}
en la vista (o mediante programación en el modelo).Generalmente no deberías preocuparte por esto.JSF (específicamente EL) al menos no lo construirá antes de lo necesario para construir, procesar o representar correctamente la vista.
¿Qué constructor se invocará para la creación de esta instancia y por qué?
El constructor predeterminado, por supuesto.Porque la especificación de Javabeans así lo dice.Todos los demás constructores nunca son utilizados por la instalación de beans administrados JSF/CDI.
Incluso entonces, no deberías preocuparte por los constructores.Será mejor que realices la inicialización en un @PostConstruct
método anotado en lugar de en un constructor.Es decir, cuando el bean es administrado por un marco de administración de bean que utiliza servidores proxy, como CDI, se puede llamar al constructor predeterminado con más frecuencia de la deseada.
No entiendo cómo se puede observar desde el código index.xhtml.
Simplemente ponga un punto de interrupción en el constructor, @PostConstruct
, o cualquier método getter/setter relevante y ejecute el proyecto en modo de depuración.Una vez que llegue al punto de interrupción, examine la pila de llamadas.Las clases y métodos involucrados generalmente tienen nombres que se autodocumentan.A continuación se muestra un ejemplo de cómo puede verse la pila de llamadas cuando se utiliza @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
...
Comience desde abajo (he eliminado todas las líneas después FacesServlet.service
ya que generalmente son irrelevantes) y lea de abajo hacia arriba.El RenderResponsePhase.execute
indica que se ejecuta durante la fase de respuesta de renderizado.El TextInstruction.write
dice que ocurrió durante la escritura del resultado de EL en el texto de plantilla así <p>#{bean.something}</p>
.El resto es simplemente cómo la implementación CDI Weld encuentra y crea una instancia del proxy y cómo, a su vez, crea una instancia de la referencia real del bean.
Si sucediera durante una fase diferente, en lugar de RenderResponsePhase.execute
he visto por ejemplo UpdateModelValuesPhase.execute
etcétera.