5 Replies Latest reply on Apr 25, 2007 11:53 AM by Per Norman

    Question regarding performance and multiple JavaBean bijecti

    Per Norman Newbie

      Hi

      We're developing a site based on MyFaces, Facelets and Seam, and now we're a little concerned about the performance - it's a bit slow. While analyzing the code I found out some strange Seam behavior.

      Background: All our Seam beans are normal JavaBeans (no EJB beans). We'r running the web application in Tomcat (no EE container).

      Case: I have a SESSION scoped bean called mainBean with (among other things) a @DataModel getter, a @DataModelSelection setter and an @In setter like the following fragment.

       @In(create = true)
       public void setWebUser(WebUserBean webUser) {
       log.debug(" === Injecting @In 'webUser' (#0 times).", bullCounter3++);
       this.webUser = webUser;
       }
      
       @DataModel
       public List<MooxObject> getMainListItems() {
       log.debug(" === Reading @DataModel 'getMainListItems' (#0 times).", bullCounter++);
       if (isCurrentList())
       return currentMainObjectAsList().getListItems();
       else
       return null;
       }
      
      
       protected MooxObject selectedListItem;
      
       @DataModelSelection("mainListItems")
       public void setSelectedListItem(MooxObject selectedListItem) {
       log.debug(" === Injecting @DataModelSelection 'setSelectedListItem' (#0 times).", bullCounter2++);
       this.selectedListItem = selectedListItem;
       }
      


      The page that uses mainBean can contain either nothing, an object or a list. We use facelets' <ui:include> to alter the page depending on what it contains.

      The strange thing is that the annotated getters and setters are called multiple times for each request. I've included three different log outputs to visualize it:

      With an empty page (no reference to @DataModel):
      [org.jboss.seam.jsf.SeamPhaseListener - 40] before phase: RESTORE_VIEW(1)
      [org.jboss.seam.jsf.SeamPhaseListener - 84] after phase: RESTORE_VIEW(1)
      [org.jboss.seam.jsf.SeamPhaseListener - 40] before phase: RENDER_RESPONSE(6)
      [com.fastsearch.w2p.moox.beans.MainBean - 48] === Injecting @In 'webUser' (54 times).
      [com.fastsearch.w2p.moox.beans.MainBean - 118] === Reading @DataModel 'getMainListItems' (27 times).
      [com.fastsearch.w2p.moox.beans.MainBean - 48] === Injecting @In 'webUser' (55 times).
      [com.fastsearch.w2p.moox.beans.MainBean - 48] === Injecting @In 'webUser' (56 times).
      [com.fastsearch.w2p.moox.beans.MainBean - 118] === Reading @DataModel 'getMainListItems' (28 times).
      [com.fastsearch.w2p.moox.beans.MainBean - 48] === Injecting @In 'webUser' (57 times).
      [org.jboss.seam.jsf.SeamPhaseListener - 84] after phase: RENDER_RESPONSE(6)
      

      The strange thing is that @DataModel getter is called twice, although never referenced. And webUser bean is injected 4 times.

      With a single object page (no reference to @DataModel):
      [org.jboss.seam.jsf.SeamPhaseListener - 40] before phase: RESTORE_VIEW(1)
      [org.jboss.seam.jsf.SeamPhaseListener - 84] after phase: RESTORE_VIEW(1)
      [org.jboss.seam.jsf.SeamPhaseListener - 40] before phase: RENDER_RESPONSE(6)
      [com.fastsearch.w2p.moox.beans.MainBean - 48] === Injecting @In 'webUser' (560 times).
      [com.fastsearch.w2p.moox.beans.MainBean - 130] === Injecting @DataModelSelection 'setSelectedListItem' (228 times).
      [com.fastsearch.w2p.moox.beans.MainBean - 118] === Reading @DataModel 'getMainListItems' (298 times).
      [com.fastsearch.w2p.moox.beans.MainBean - 48] === Injecting @In 'webUser' (561 times).
      [com.fastsearch.w2p.moox.beans.MainBean - 48] === Injecting @In 'webUser' (562 times).
      [com.fastsearch.w2p.moox.beans.MainBean - 130] === Injecting @DataModelSelection 'setSelectedListItem' (229 times).
      [com.fastsearch.w2p.moox.beans.MainBean - 268] ** MainBean - setCurrentObject
      [com.fastsearch.w2p.moox.beans.MainBean - 118] === Reading @DataModel 'getMainListItems' (299 times).
      [com.fastsearch.w2p.moox.beans.MainBean - 48] === Injecting @In 'webUser' (563 times).
      [com.fastsearch.w2p.moox.beans.MainBean - 48] === Injecting @In 'webUser' (564 times).
      [com.fastsearch.w2p.moox.beans.MainBean - 118] === Reading @DataModel 'getMainListItems' (300 times).
      [com.fastsearch.w2p.moox.beans.MainBean - 48] === Injecting @In 'webUser' (565 times).
      [com.fastsearch.w2p.moox.beans.MainBean - 48] === Injecting @In 'webUser' (566 times).
      [com.fastsearch.w2p.moox.beans.MainBean - 118] === Reading @DataModel 'getMainListItems' (301 times).
      [com.fastsearch.w2p.moox.beans.MainBean - 48] === Injecting @In 'webUser' (567 times).
      [com.fastsearch.w2p.moox.beans.MainBean - 48] === Injecting @In 'webUser' (568 times).
      [com.fastsearch.w2p.moox.beans.MainBean - 118] === Reading @DataModel 'getMainListItems' (302 times).
      [com.fastsearch.w2p.moox.beans.MainBean - 48] === Injecting @In 'webUser' (569 times).
      [org.jboss.seam.jsf.SeamPhaseListener - 84] after phase: RENDER_RESPONSE(6)
      

      Now we have 5 @DataModel gets and 10 @In injections. The @DataModelSelection is injected twice.

      With a list (two reference to @DataModel in one Tomahawk <t:dataTable>):
      [org.jboss.seam.jsf.SeamPhaseListener - 40] before phase: RESTORE_VIEW(1)
      [org.jboss.seam.jsf.SeamPhaseListener - 84] after phase: RESTORE_VIEW(1)
      [org.jboss.seam.jsf.SeamPhaseListener - 40] before phase: RENDER_RESPONSE(6)
      [com.fastsearch.w2p.moox.beans.MainBean - 48] === Injecting @In 'webUser' (570 times).
      [com.fastsearch.w2p.moox.beans.MainBean - 118] === Reading @DataModel 'getMainListItems' (303 times).
      [com.fastsearch.w2p.moox.beans.MainBean - 48] === Injecting @In 'webUser' (571 times).
      [com.fastsearch.w2p.moox.beans.MainBean - 48] === Injecting @In 'webUser' (572 times).
      [com.fastsearch.w2p.moox.beans.MainBean - 268] ** MainBean - setCurrentObject from: [USER/USER:68 (norman)] to: [LIST/LIST:0 (lists.alias.members)]
      [com.fastsearch.w2p.moox.serviceinterfaces.ListServiceDecorator - 496] Populating list with 8 members...
      [com.fastsearch.w2p.moox.beans.MainBean - 118] === Reading @DataModel 'getMainListItems' (304 times).
      [com.fastsearch.w2p.moox.beans.MainBean - 118] === Reading @DataModel 'getMainListItems' (305 times).
      [com.fastsearch.w2p.moox.beans.MainBean - 118] === Reading @DataModel 'getMainListItems' (306 times).
      [com.fastsearch.w2p.moox.beans.MainBean - 118] === Reading @DataModel 'getMainListItems' (307 times).
      [com.fastsearch.w2p.moox.beans.MainBean - 118] === Reading @DataModel 'getMainListItems' (308 times).
      [com.fastsearch.w2p.moox.beans.MainBean - 118] === Reading @DataModel 'getMainListItems' (309 times).
      [com.fastsearch.w2p.moox.beans.MainBean - 48] === Injecting @In 'webUser' (573 times).
      [com.fastsearch.w2p.moox.beans.MainBean - 48] === Injecting @In 'webUser' (574 times).
      [com.fastsearch.w2p.moox.beans.MainBean - 130] === Injecting @DataModelSelection 'setSelectedListItem' (230 times).
      [com.fastsearch.w2p.moox.beans.MainBean - 118] === Reading @DataModel 'getMainListItems' (310 times).
      [com.fastsearch.w2p.moox.beans.MainBean - 48] === Injecting @In 'webUser' (575 times).
      [com.fastsearch.w2p.moox.beans.MainBean - 48] === Injecting @In 'webUser' (576 times).
      [com.fastsearch.w2p.moox.beans.MainBean - 130] === Injecting @DataModelSelection 'setSelectedListItem' (231 times).
       (and a fiew more hundred injections...)
      [com.fastsearch.w2p.moox.beans.MainBean - 118] === Reading @DataModel 'getMainListItems' (425 times).
      [com.fastsearch.w2p.moox.beans.MainBean - 48] === Injecting @In 'webUser' (797 times).
      [com.fastsearch.w2p.moox.beans.MainBean - 48] === Injecting @In 'webUser' (798 times).
      [com.fastsearch.w2p.moox.beans.MainBean - 130] === Injecting @DataModelSelection 'setSelectedListItem' (342 times).
      [com.fastsearch.w2p.moox.beans.MainBean - 118] === Reading @DataModel 'getMainListItems' (426 times).
      [com.fastsearch.w2p.moox.beans.MainBean - 48] === Injecting @In 'webUser' (799 times).
      [org.jboss.seam.jsf.SeamPhaseListener - 84] after phase: RENDER_RESPONSE(6)
      

      It seems like every time mainBean is accessed (several times in each row in the table) it's reinitialized.


      And now my questions:

      * Are we doing something terribly wrong? Why do we get all these injections?

      * For best performance - Should we use several small beans with a lot of dependencies, or a fiew bigger beans?

      * For best performance - Should we try to have big scopes (like SESSION) to reduce the number of bean instanses, or should we try to minimize the scope (to EVENT)?


      Finally I'd like to say that except for this injection mystery, Seam really rocks! (I can't imagine JSF without it...)


        • 1. Re: Question regarding performance and multiple JavaBean bij
          fhh Expert

          Are you accessing your datamodel as #{mainBean.mainListItems} or #{mainListItems}?

          Regards

          Felix

          • 2. Re: Question regarding performance and multiple JavaBean bij
            Per Norman Newbie

            The table references the model with:
            <t:dataTable value="#{mainListItems}" var="listItem"

            In the table i use mostly the listItem variable like:
            <h:outputText value="#{messages[listItem.title]}" />

            But also mainBean properties directly like:
            <t:column rendered="#{mainBean.listContainsType == 'USER'}">

            • 3. Re: Question regarding performance and multiple JavaBean bij
              Per Norman Newbie

              I've done some research and a mini test application to show my results:

              The bean

              import org.jboss.seam.annotations.In;
              import org.jboss.seam.annotations.Logger;
              import org.jboss.seam.annotations.Name;
              import org.jboss.seam.annotations.Out;
              import org.jboss.seam.log.Log;
              import javax.faces.context.FacesContext;
              
              @Name("testBean")
              public class TestBean {
               @Logger Log log;
              
               @In
               public void setFacesContext(FacesContext facesContext) {
               log.debug(" === Inject: @In setFacesContext.");
               }
              
               @Out
               private String testValue = "test value";
              
               public String getTestValue() {
               return testValue;
               }
              }
              


              The view
              <?xml version="1.0" ?>
              <jsp:root version="2.0"
               xmlns="http://www.w3.org/1999/xhtml"
               xmlns:jsp="http://java.sun.com/JSP/Page"
               xmlns:h="http://java.sun.com/jsf/html"
               xmlns:f="http://java.sun.com/jsf/core"
               xmlns:ui="http://java.sun.com/jsf/facelets">
               <html>
               <body>
               <f:view>
               <h1><h:outputText value="Test Page"/></h1>
               <h:form id="form1">
               <h1>Bean access</h1>
               <h:outputText value="Property: #{testBean.testValue}" /><br/>
               <h:outputText value="Property: #{testBean.testValue}" /><br/>
               <h:outputText value="@Out Value: #{testValue}" /><br/>
               <h:outputText value="@Out Value: #{testValue}" /><br/>
               <h:outputText value="@Out Value: #{testValue}" /><br/>
               </h:form>
               </f:view>
               </body>
               </html>
              </jsp:root>
              


              The result is that facesContext is injected 4 times - twice for each #{testBean.testValue}. Adding another #{testBean.testValue} will force two more injections!

              The #{testValue} on the other hand does not enforce any injections.

              Now I wonder:
              * Is this behavior a bug?
              * Do I get this behaviour because I'm using JavaBeans instead of EJB3 SessionBeans?

              Also:
              * To get the @Out outjection to work, I must first access the bean (with #{testBean.testValue} for instance). Is there another way to "wake up" the bean so that @Out works?

              • 4. Re: Question regarding performance and multiple JavaBean bij
                Pete Muir Master

                 

                "pnorman4" wrote:
                The result is that facesContext is injected 4 times - twice for each #{testBean.testValue}. Adding another #{testBean.testValue} will force two more injections!

                The #{testValue} on the other hand does not enforce any injections.


                Each time that you call a method on your Seam component, Seam will biject as required. When the method is complete Seam disinjects the any injections. So, each time you call #{testBean.testValue}, you get an injection. As for why each #{testBean.testValue} causes two injections, that's probably down to JSF/Facelets evaluating the binding twice.

                By the time you access #{testValue} on your page it has been outjected by testBean and so exists as a contextual variable and hence doesn't access the bean at all.


                Now I wonder:
                * Is this behavior a bug?


                Why do you wonder that?

                * Do I get this behaviour because I'm using JavaBeans instead of EJB3 SessionBeans?


                No.

                Also:
                * To get the @Out outjection to work, I must first access the bean (with #{testBean.testValue} for instance). Is there another way to "wake up" the bean so that @Out works?


                Look at using @Factory or @Create (there are examples of both in examples directory.

                In general we (Gavin) have done a very good job of making Seam fast - there are discussions about this on the forum, take a look through. The normal candidate for slowness is in your use of the ORM.

                • 5. Re: Question regarding performance and multiple JavaBean bij
                  Per Norman Newbie

                   


                  Each time that you call a method on your Seam component, Seam will biject as required. When the method is complete Seam disinjects the any injections. So, each time you call #{testBean.testValue}, you get an injection.


                  OK. I hadn't understood the difference between @Out and property access.

                  I think the problem is we're using Seam the wrong way. We're mixing up session beans and entity beans (because they're all JavaBeans to us). We're accessing properties on complex controller beans with lots of injections (dependencies to other beans), instead of using simple entity objects. This is triggering long chains of injections repeated multiple times, which is slowing down our app.

                  I will now redesign our beans.

                  Thanx for your time and good support!