问题
Consider example of JSF based web-app hello1
from official tutorial with addition constructor in managed bean. The follow 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>
and modidfied managed bean 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;
}
}
There are two public constructors. Let we deploy this app on server and sent initial request, type the name in inputText
and click submit
. There is postback request after submit
click. Hence, as written in tutroial, we have the following subphase of execute phase:
- The application view is built or restored.
- The request parameter values are applied.
- Conversions and validations are performed for component values.
- Managed beans are updated with component values.
- Application logic is invoked.
At what phase instance of managed bean will be created?
What constructor will be invoked for this instance creation and why? I dont understand how it can be observe from the index.xhtml
code.
回答1:
At what phase instance of managed bean will be created?
No one specifically. It's constructed for the first time when an arbitrary EL expression needs to reference the managed bean for the first time while the bean instance isn't present in its scope. This is not dependent on any particular faces event. This can be during restore view phase (the first phase), but this can also be as good during render response phase (the last phase), or any other phase in between.
This all depends on how and where the bean is referenced in EL context via #{bean.xxx}
in the view (or programmatically in the model). You should generally not worry about this. JSF (specifically EL) will at least not construct it sooner than necessary in order to properly build or process or render the view.
What constructor will be invoked for this instance creation and why?
The default constructor, of course. Because the Javabeans specification says so. All other constructors are never used by JSF/CDI managed bean facility.
Even then, you should not be worrying about constructors. You'd better perform initialization in a @PostConstruct
annotated method instead of in a constructor. Namely, when the bean is managed by a bean management framework which uses proxies, such as CDI, the default constructor may be called more often than desired.
I don't understand how it can be observe from the index.xhtml code.
Just put a breakpoint in constructor, @PostConstruct
, or whatever relevant getter/setter method and run the project in debug mode. Once the breakpoint hits, examine the call stack. The involved classes and methods have generally rather self-documenting names. Here's an example how the call stack can look like when you're using @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
...
Start at the bottom (I've stripped all lines after FacesServlet.service
as those are generally irrelevant) and read from bottom to top. The RenderResponsePhase.execute
tells that it's executed during render response phase. The TextInstruction.write
tells that it occurred during writing the outcome of EL in template text like so <p>#{bean.something}</p>
. The remainder is just how the CDI implementation Weld is finding and instantiating the proxy and how it is in turn instantiating the actual bean reference.
If it happened during a different phase, you'd instead of RenderResponsePhase.execute
have seen for example UpdateModelValuesPhase.execute
and so on.
来源:https://stackoverflow.com/questions/20035681/at-which-phase-is-managed-bean-constructed-and-which-constructor-is-used