11 Replies Latest reply on Jul 13, 2011 2:49 PM by yangju.richard.yang.pearson.com

    Dependent beans doubts

    wujek
      Hi,
      suppose we have something like this:

      // @Dependent by default
      public class DependentBean {}

      @ApplicationScoped
      public class Service {

          @Inject
          private Instance<DependentBean> beans;

          public int serve() {
              DependentBean bean = beans.get();
              // do whatever
              return 17;
          }
      }

      We have a service that is application scoped, but internally it uses a bean that must be created for each service call, basically meaning a new instance is created per client call. The questions:

      1. Is this a valid usage of Instance? Does this make sense, or is this a CDI antipattern?

      2. In point 6.4.1 in the specs (last bullet), we read:
      "An instance of a bean with scope @Dependent obtained by direct invocation of an Instance is a dependent object of the instance of Instance."
      I am not sure, but I couldn't find when the dependent instances are destroyed, so I assume that they are destroyed when the Instance<> is destroyed, and in turn this is destroyed when the instance that contains it is destroyed, and as it is an @ApplicationScoped bean, it will be destroyed when CDI is shut down.
      So the question: if my assumptions are correct, this would mean that during the whole lifetime of the application, new DependentBeans will be created for each service call, and the application can run out of memory at some point, if it runs long enough?
      Is this correct? Please prove me wrong.

      Regards,
      Wujek
        • 1. Re: Dependent beans doubts
          marcelkolsteren

          Interesting case. I don't have an opinion about your first point, but I want to react on the second. Having read your quote from the spec (6.4.1), I'd expect that during the first invocation of beans.get(), a new instance of DependentBean is created, and added as a dependent object of the instance of Instance, which is stored in the beans field. My initial thought was that during the second invocation of the beans.get() method, it would just find and return the same dependent object again.


          Just to be sure, I created a small Maven project with an Arquillian test. I uploaded it here. It contains the beans of your example, where the Service.serve method has been modified, so that it returns a unique id of the object returned by beans.get():



             public String serve()
             {
                return beans.get().toString();
             }



          The test case injects the Service bean, and calls serve() ten times. It expects to get the same result 10 times, but ... it fails. The second invocation already gives another result than the first one, which proves that at least for Weld 1.1.0.Beta1, your assumption is true, and mine is false.


          So now I share your concerns about the increasing memory consumption. :-)

          • 2. Re: Dependent beans doubts
            wujek
            Thanks for your answer.
            Yes, that's how Instance<DependentBean> should behave, at least that's my understanding from the specs - each invocation a *fresh new* instance is created and returned.
            We use this Instance<> trick in a few places (not too many for now, so if someone says it is a CDI antipattern and can provide a better solution, it should be an easy fix) - we do it every time we need a bean of norrower scope inside a bean of a broader scope. For example, once you have a @SessionScoped bean and inside you want to use something that comes from the http request, we would have it like this:

            @SessionScoped
            public class SessionBean {

                @Inject
                private Instance<RequestBean> beans;

                public void doSth() {
                    RequestBean bean = beans.get();
                    ...
                }
            }

            As far as I know, there is no other way to perform such injection correctly. Without Instance, the RequestBean would only be correct on the first invocation (maybe even not) and incorrect for any further calls.
            I think it is a pretty common pattern that a singleton / application scoped service uses norrower beans. In the example case, we could simply use new to create new instances of beans, but there wouldn't be managed, and they also have some stuff injected (possibly going quite deep in the object graph), and that would mean giving up a lot of CDI goodness.
            A workaround would be to make everything only as scoped as the norrowest bean in its injection chain, but this doesn't seem reasonable, as pretty much everything (at least for us) would be @Dependent, so the service would be created for each call, which we absolutely don't want.

            The question is also not only how Weld behaves - it is an implementation of CDI after all, and not everything is specified in the CDI document, and we don't want to rely on unportable behavior (some of our clients have Resin servers, they might want to be able to deploy our app there, and they use CanDI); the question really is - what the specs has to say about it. The behavior needs to be portable. I tried really hard to find answers, but I failed. It's a pity that Gavin seems to have abandoned any 'support' for CDI (maybe I am wrong, but he used to come over and answer doubts).

            Regards.
            • 3. Re: Dependent beans doubts
              marcelkolsteren

              Ok, this extra information made me have an opinion about your first point: this usage of Instance, If you use it everywhere where you need to do injection of a narrower scoped bean into a field of a wider scoped bean, I'd call that an antipattern. In most cases, you don't need the Instance<T>, you could just use T as the type of the field. In your example with the Request scoped bean injected into the session scoped bean, it would be safe to just have


              private RequestBean bean;



              The CDI container will ensure that the bean field refers to the current bean instance, i.e. to the instance that belongs to the current context of the request scope. So I don't agree with your remark about the requestBean not being correct. Try it without Instance, and you'll see that it just works. If you use your pattern, the code will be overly verbose, and you'd not be using the strength of CDI.


              I also have some additional thoughts about the second point (the memory consumption problem). The only hard requirement that the specification gives, is that the dependent objects of the Instance instance are destroyed by the container when the application scoped bean is destroyed, so at application termination time. However, the CDI container is allowed to destroy the dependent objects at some earlier point in time, according to section 6.4.2:



              Finally, the container is permitted to destroy any @Dependent scoped contextual instance at any time if the instance is no longer referenced by the application (excluding weak, soft and phantom references).

              So in your example, the container will create a new instance of DependentBean for each serve() call, but it is allowed to destroy this instance as soon as the application doesn't refer it any more. Don't know at what point in time Weld would destroy the dependent bean instances in this case. But for a portable application, you can't depend on it anyway.

              • 4. Re: Dependent beans doubts
                wujek

                Hi.
                Regarding the memory usage - I noticed that line that you quote, but this is not portable (as you mentioned), as it is no a 'must requirement'. So I would say the issue is still open - not everyone everywhere will use Weld.


                Regarding second point - don't forget that @Dependent beans are not proxied. I agree, I went too far in the Session / Request example, it doesn't make sense as you explain - thanks for the remainder. Then again, what about @Dependent beans injected into @ApplicationScoped beans? What is the de-facto standard or idiom for that? Or is this idea stupid anyways?


                Regards.

                • 5. Re: Dependent beans doubts
                  marcelkolsteren

                  Going back to your initial example. Even knowing that @Dependent beans are not proxied, I'd normally do it just like this:


                  @Inject
                  private DependentBean bean



                  Why would you need a fresh instance of the dependent bean for each serve call? Maybe because the dependent bean is not thread safe? In that case, it would be advisable to use a stateless session bean instead, because then you are sure that the dependent bean can never be called by multiple threads simultaneously, independent of how you inject it. Some other (and better) reasons for obtaining a contextual instance by programmatic lookup are mentioned in section 4.10 of the Weld documentation:



                  • the bean type or qualifiers vary dynamically at runtime, or

                  • depending upon the deployment, there may be no bean which satisfies the type and qualifiers, or

                  • we would like to iterate over all beans of a certain type.



                  Maybe the documentation should warn that this programmatic lookup could lead to excessive memory consumption if the dependent bean has scope @Dependent (which is the default)?


                  I hope that other forum readers (and hopefully also a Weld developer) will also give their view on this.

                  • 6. Re: Dependent beans doubts
                    wujek

                    This will not work - checked. It will be injected only once when the 'outer' object is created, and live forever until the owner is closed.
                    Why do we need dependent beans? Just because we need to scope certain things per client, that's all, it doesn't have anything to do with thread-safety, it is just data scoping.
                    Why not make it an SLSB - c'mon, we don't need it to be an EJB. And this would pretty much mean that everything would need to be an EJB, but even then - we would need to meke it Statefull EJBs as we do need state per client call.
                    Is this really such an unorthodox requirement - a service with call-scoped objects?


                    Regards.

                    • 7. Re: Dependent beans doubts
                      marcelkolsteren

                      I know that only one dependent object will be created when you just inject it plainly. However, I made an assumption that I didn't verify. I assumed that the dependent bean was designed as a stateless bean. In that case, the simple injection just works (if the dependent bean is thread safe).


                      Ok, so your intention is to use a stateful dependent bean. And you want it to be scoped to the client call. But that's what the request scope is for, so in that case you would not use the dependent scope at all. A dependent object extends the state of the object in which it is injected, so in fact it becomes part of the state of it's host.

                      • 8. Re: Dependent beans doubts
                        wujek

                        Ok. So Request scope - but do you remember, I asked about RequestScope a few days ago, whether it is available for local beans - the only kind that we have. You answered that the scope is propagated with the call - if this is true, I guess I could use the request scope for beans per service method call that are stateful, right? Please verify.
                        Then a question comes to my mind - when would I use a @Dependent bean? What is the use case?


                        Thank you very much for the conversation and your time for now, it has been enlightening for me at a few points.


                        Regards.

                        • 9. Re: Dependent beans doubts
                          marcelkolsteren

                          You're welcome, always good to enlighten each other. :-)


                          The request scope is indeed propagated into local EJB business methods. Of all available scopes, the request scope fits best to the thoughts you have about state that is scoped to the client call. But that doesn't mean it's a perfect fit. Looking at the request context lifecycle (section 6.7.1 of the CDI spec), you see that the request starts and ends at container boundaries, or where an internal asynchronous event needs to be handled. So this request scope is probably wider than the client call scope that you're thinking about. In fact it all depends on how you define the client. If you're in a servlet environment and the browser is the client, then the request scope matches with client call scope. However, if you think of any other component that calls my local EJB business method as the client, then the request scope is wider than the client call scope.


                          By the way, this thread is floating away from the initial doubts about using dependent beans in combination with programmatic instance lookup (the memory consumption issue). I think the both of us are quite sure that the doubts are valid, so let's finish here and wait for others to agree or disagree with us. The whole client call scope discussion is another subject that deserves another thread (if the request scope doesn't fit your needs).

                          • 10. Re: Dependent beans doubts
                            wujek
                            Hi Marcel,
                            thank you for your previous posts.
                            I have some more input now (I was distracted from this topic for a while).
                            The idea that Instance<T> allows me to produce stateful dependent beans for each client call came from my experiences with Guice and its Provider<T>. As it turns out, this interface made it to JSR 330, Provider<T>, which in turn is extended by Instance<T>. The JavaDoc for Provider<T> in 330 say:

                            Compared to injecting T directly, injecting Provider<T> enables:

                                * retrieving multiple instances.
                                * lazy or optional retrieval of an instance.
                                * breaking circular dependencies.
                                * *abstracting scope so you can look up an instance in a smaller scope from an instance in a containing scope.*

                            Please see the last bullet-point - this seems exactly the use case I am trying to represent!
                            So, on one side, Instance<T> extends Provider<T> so I would assume that where the superclass is good to be used, also the subclass can be used, but on the other hand it has this worrying feature we talked about - of holding on to the references as long as the containing bean exists - in our case @ApplicationScoped / SLSB.

                            As for the @RequestScope, I think your tip is great and will work for us - we have a rich webapp that sits in the servlet layer, making calls to our services through a facade modelled with SLSBs. So, each call actually would traverse container boundaries; the only thing is that all our EJBs are local beans, so I don't know how this would behave. What do you think?
                            I hope to have a few loose hours this week, and will attempt to see how all this works together (will try to blow up the application with bombarding my EJB with requests to make the memory usage grow, and will also test to see if @RequestScoped works for our use case).

                            Again, thank you very much for your time.

                            Wujek.
                            • 11. Re: Dependent beans doubts
                              yangju.richard.yang.pearson.com

                              Wujek:
                              Have you found a solution to your problem? I have similar issue to solve. See detail in this discussion:
                              http://seamframework.org/Community/DoesJavaxinjectProvidergetAlwaysReturnANewInstance


                              If you have any insight, please let me know.


                              Thanks.


                              Richard