14 Replies Latest reply on Feb 17, 2010 12:18 PM by pmuir

    Question regarding CDI's proxy class generation

    jeff.howard
      When poking around in a JSF2 + weld webapp I'm working on I noticed something rather frightening that weld appears to be doing.  (At least I think it's weld's doing, feel free to correct me)  Anyway, I was watching in the debugger as CDI managed beans were being created and stuffed into a scope and I noticed that every time CDI instantiates a managed bean (the same managed bean class) it is creating a new proxy class for it.  I've watched the classname on the proxy go from TestBean_$$javassist_7 to TestBean_$$javassist_128 pretty quickly as the application is running.  Is this normal?  If so, it has some rather serious implications for the JVM's permgen space.

      Thanks!
      -- Jeff Howard
        • 1. Re: Question regarding CDI's proxy class generation
          ashishlin

          I think the correct term is Client Proxies and more explanation can be found here. Whether or not they are created each time depends on the Scope of Bean.

          • 2. Re: Question regarding CDI's proxy class generation
            nickarls

            I proxies are used, they are cached. Can you try injecting 3 request scoped beans into another bean and then outputting them, they should be the same. If there is indeed a problem in the cache-lookup, it would quickly eat up memory...

            • 3. Re: Question regarding CDI's proxy class generation
              nickarls

              You will have to give more details - I tried a simple case of injecting two instances of the same proxied bean and they returned the same proxy.

              • 4. Re: Question regarding CDI's proxy class generation
                jeff.howard

                Ok.  I'll see if I can put together a simplified code example showing this behavior.


                Thanks!

                • 5. Re: Question regarding CDI's proxy class generation
                  jeff.howard

                  It appears that the problem I'm seeing is specific to the (rather complex) environment the code is running in at work.  I just built a test war from scratch to demonstrate the issue and I'm unable to reproduce it in this new setup... 

                  • 6. Re: Question regarding CDI's proxy class generation
                    swd847

                    In your rather complex environment are you adding beans through the SPI?

                    • 7. Re: Question regarding CDI's proxy class generation
                      jeff.howard

                      Stuart,
                      If I understand what you're asking then no.  The only SPI extension in the environment right now is the CDI wrapper for the JSF view scope (based directly on the example by Steven Verborgh) which works perfectly in the test war I created this morning.  Most of the complexity in my environment is due to dancing around with library dependencies for some proprietary code that I have to work with. It's not pretty  :)

                      • 8. Re: Question regarding CDI's proxy class generation
                        nickarls

                        If you do find out the case (e.g. decorators/interceptors), let us know.

                        • 9. Re: Question regarding CDI's proxy class generation
                          jeff.howard

                          Ok, I've done some more digging and I'm able to reproduce the behavior I was asking about with a simple war on a vanilla jboss 6 server.


                          Here's a brief explanation.  I can provide the code if you need it.
                          I've got a @Named bean that has a property that has an interceptor on it. I've also got the previously mentioned custom view scope extension which allows me to look at the beans as they are being created and added to the scope without hacking directly on weld.  I borrowed from the AbstractMapContext to make certain that beans are being created approximately the same way in the custom view scope as in the built-in weld scopes:


                             public <T> T get(Contextual<T> contextual, CreationalContext<T> creationalContext) {
                                  String id = getId(contextual);
                                  System.out.println("Id = "+id);
                                  ContextualInstance<T> beanInstance = (ContextualInstance<T>)(getViewMap().get(id));
                                  if (beanInstance!=null){
                                      T ret = beanInstance.getInstance();
                                      System.out.println("retrieving object of class "+ret.getClass().getName());
                                      return ret;
                                  } else if (creationalContext!=null){
                                      T instance = contextual.create(creationalContext);
                                      if (instance!=null){
                                          beanInstance = new SerializableContextualInstanceImpl<Contextual<T>, T>(contextual, instance, creationalContext);
                                          getViewMap().put(id,beanInstance);
                                          System.out.println("Creating object of class "+instance.getClass().getName());
                                          return instance;
                                      }
                                  }
                                  return null;
                              }
                              protected static String getId(Contextual<?> contextual) {
                                  return Container.instance().deploymentServices().get(ContextualStore.class).putIfAbsent(contextual);
                              }




                          In my test jsf page I have a line like:



                          Retreiving a view scoped object with classtype #{testBean.class.name}




                          When I load and reload the page, forcing a new view scope to be created, the class name reported in the JSF output remains constant, as you would expect. 




                          Retreiving a view scoped object with classtype TestBean_$$_javassist_58





                          Here's the odd part.  The println statements in the context's get method above tell a different story:



                          21:07:14,481 INFO  [STDOUT] Id = org.jboss.weld.bean-flat-ManagedBean-class TestBean
                          21:07:14,486 INFO  [STDOUT] Creating object of class TestBean_$$_javassist_59
                          21:07:14,487 INFO  [STDOUT] Intercepting
                          21:07:17,857 INFO  [STDOUT] Id = org.jboss.weld.bean-flat-ManagedBean-class TestBean
                          21:07:17,860 INFO  [STDOUT] Creating object of class TestBean_$$_javassist_60
                          21:07:17,860 INFO  [STDOUT] Intercepting
                          21:07:20,796 INFO  [STDOUT] Id = org.jboss.weld.bean-flat-ManagedBean-class TestBean
                          21:07:20,804 INFO  [STDOUT] Creating object of class TestBean_$$_javassist_61
                          21:07:20,805 INFO  [STDOUT] Intercepting
                          21:09:21,945 INFO  [STDOUT] Id = org.jboss.weld.bean-flat-ManagedBean-class TestBean
                          21:09:21,951 INFO  [STDOUT] Creating object of class TestBean_$$_javassist_62
                          21:09:21,955 INFO  [STDOUT] Intercepting



                          So if I'm seeing what I think I'm seeing, the class type of the generated proxy being handed to JSF remains constant but the get method in the custom context is generating a new class type every time a new context instance is created...  I'm thoroughly confused!  :)


                          • 10. Re: Question regarding CDI's proxy class generation
                            nickarls

                            How is the output if the interceptor is not used?

                            • 11. Re: Question regarding CDI's proxy class generation
                              jeff.howard

                              The context prints the following in the get() method:


                              10:06:34,261 INFO  [STDOUT] Id = org.jboss.weld.bean-flat-ManagedBean-class TestBean
                              10:06:34,262 INFO  [STDOUT] Creating object of class TestBean
                              10:06:37,862 INFO  [STDOUT] Id = org.jboss.weld.bean-flat-ManagedBean-class TestBean
                              10:06:37,862 INFO  [STDOUT] Creating object of class TestBean
                              10:06:40,728 INFO  [STDOUT] Id = org.jboss.weld.bean-flat-ManagedBean-class TestBean
                              10:06:40,728 INFO  [STDOUT] Creating object of class TestBean
                              



                              The rendered page shows:


                              Retreiving a view scoped object with classtype TestBean_$$_javassist_76
                              

                              • 12. Re: Question regarding CDI's proxy class generation
                                jeff.howard

                                Should a JIRA be filed for this?

                                • 13. Re: Question regarding CDI's proxy class generation
                                  nickarls

                                  If it's reproducible with any of the built-in contexts, yes ;-)

                                  • 14. Re: Question regarding CDI's proxy class generation
                                    pmuir

                                    Jeff Howard wrote on Feb 10, 2010 21:49:


                                    Should a JIRA be filed for this?


                                    Yes, please file a JIRA for this, we'll take a look. We are going to need a simple test application to reproduce, and detailed instructions.