jsfmanaged-beanconstruction

At which phase is managed bean constructed and which constructor is used


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:

  1. The application view is built or restored.
  2. The request parameter values are applied.
  3. Conversions and validations are performed for component values.
  4. Managed beans are updated with component values.
  5. 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.


Solution

  • 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.