[cdi-dev] Destroying @Stateless proxies obtained via CDI.current().select()

John D. Ament john.d.ament at gmail.com
Wed May 11 20:49:32 EDT 2016


On Wed, May 11, 2016 at 7:05 AM Martin Kouba <mkouba at redhat.com> wrote:

> Dne 11.5.2016 v 11:56 arjan tijms napsal(a):
> > Hi,
> >
> > On Wed, May 11, 2016 at 11:43 AM, Martin Kouba <mkouba at redhat.com
> > <mailto:mkouba at redhat.com>> wrote:
> >
> >     I don't think so. Remember that Instace is more like a "factory" and
> >     not only for @Dependent objects. What would actually close() do?
> >
> >
> > I'd intuitively say release and where appropriate destroy all beans that
> > were created from that particular instance of uhm Instance. But maybe
> > the existing semantics of Instance aren't a good fit for that.
> >
> > Thinking out loud, maybe an AutoInstance variant?
> >
> > try (AutoInstance<Foo> fooInstance =
> CDI.current().autoSelect(Foo.class)) {
> >
> >       Foo foo = fooInstance.get();
> >       foo.bar();
> > }
>
> Well, I'm not sure it's worth adding a new interface + method in CDI API
> if the only purpose is to call Instance.destroy() (or possibly release()
> - see cdi/pull/286) automatically.
>
> Even now it's possible to have a wrapper/helper class for this, e.g.
> something like:
>
> class AutoDestroyable<T> implements AutoCloseable {
>
>    static AutoDestroyable<T> from(Instance<T> instance) {
>      return new AutoDestroyable(instance);
>    }
>
>    private final Instance<T> instance;
>
>    private final T value;
>
>    private AutoDestroyable(Instance<T> instance) {
>      this.instance = instance;
>      this.value = instance.get();
>    }
>
>    T get() {
>      return value;
>    }
>
>    void close() {
>       instance.destroy(value);
>    }
>
> }
>
> try (AutoDestroyable<Foo> destroyableFoo =
> AutoDestroyable.from(CDI.current().select(Foo.class))) {
>    Foo foo = destroyableFoo.get();
>    foo.bar();
> }
>
>
To accomplish this without a spec change, means that essentially every app
in the world needs this utility.  Its more scalable to write the fix once
and get it in the spec.


> >
> > autoSelect could even throw early if the selected bean is not dependent
> > scoped. But as mentioned, just thinking out loud here.
> >
> > Kind regards,
> > Arjan Tijms
> >
> >
> >
> >     Also the users would be tempted to use this for injected Instance
> >     which does not make sense.
> >
> >
> >         try (Instance<Foo> fooInstance =CDI.current().select(Foo.class))
> {
> >
> >               Foo foo = fooInstance.get();
> >               foo.bar();
> >         }
> >
> >         Kind regards,
> >         Arjan Tijms
> >
> >
> >
> >
> >              Martin
> >
> >              Dne 11.5.2016 v 10:40 arjan tijms napsal(a):
> >
> >                  Hi Martin,
> >
> >                  Thanks for the swift action and the reference. I do
> >         have one more
> >                  question looking at the test that was added. It now
> >         uses this SLSB:
> >
> >                  @Stateless
> >                  public class SLSessionBean {
> >
> >                        public void ping(){
> >                        }
> >
> >                        static final AtomicBoolean DESTROYED = new
> >         AtomicBoolean();
> >
> >                        @PreDestroy
> >                        public void destroy() {
> >                            DESTROYED.set(true);
> >                        }
> >                  }
> >
> >                  The assertion in the test is that the (a?) SLSB is
> actually
> >                  destroyed,
> >                  but wasn't the idea that only the internal reference is
> >                  destroyed, and
> >                  the bean just stays in the pool?
> >
> >                  Here it looks like the code intends to destroy a random
> >         SLSB
> >                  instance
> >                  from the pool. (random, since I guess an internal
> >         reference doesn't
> >                  stick to the same actual instance of a SLSB, otherwise
> >         you would get
> >                  stateful like semantics).
> >
> >                  Or did I miss something?
> >
> >                  Kind regards,
> >                  Arjan Tijms
> >
> >
> >
> >
> >                  On Wed, May 11, 2016 at 9:11 AM, Martin Kouba
> >         <mkouba at redhat.com <mailto:mkouba at redhat.com>
> >                  <mailto:mkouba at redhat.com <mailto:mkouba at redhat.com>>
> >                  <mailto:mkouba at redhat.com <mailto:mkouba at redhat.com>
> >         <mailto:mkouba at redhat.com <mailto:mkouba at redhat.com>>>> wrote:
> >
> >                       Hi Arjan,
> >
> >                       I believe it's a Weld bug - you should be able to
> use
> >                       Instance.destroy() to discard an internal SLSB
> >         proxy. See also
> >                       "Lifecycle of stateless and singleton session
> >         beans" [1]. Tomas
> >                       Remes created WELD-2148 to track this issue [2].
> >
> >                       Also the "leak" is an expected behaviour. See for
> >         example
> >                  WELD-920
> >                       [3] discussion.
> >
> >                       Martin
> >
> >                       [1]
> >
> http://docs.jboss.org/cdi/spec/1.2/cdi-spec.html#stateless_lifecycle
> >
> >                       [2]
> >         https://issues.jboss.org/browse/WELD-2148
> >
> >                       [3]
> >         https://issues.jboss.org/browse/WELD-920
> >
> >                       Dne 10.5.2016 v 17:11 arjan tijms napsal(a):
> >
> >                           Hi,
> >
> >                           Given a simple @Stateless bean:
> >
> >                           @Stateless
> >                           public class Foo {
> >                                 public void bar() {}
> >                           }
> >
> >                           Then requesting an instance of this via CDI as
> >         follows:
> >
> >                           Foo foo =
> CDI.current().select(Foo.class).get();
> >
> >                           Causes a lot of leaked proxy instances (at
> >         least on
> >                  Weld). Now
> >                           what I
> >                           guess needs to be done is destroying the
> >         proxy, taking
> >                  Antoine's
> >                           answer
> >                           here as a lead:
> >
> http://stackoverflow.com/questions/28767536/scope-of-stateless-bean
> >
> >                           Only the following throws an
> >                  UnsupportedOperationException (on Weld
> >                           2.3.2, haven't tested OWB yet)
> >
> >                           Instance<Foo> fooInstance
> >         =CDI.current().select(Foo.class);
> >                           Foo foo = fooInstance.get();
> >                           foo.bar();
> >                           fooInstance.destroy(foo);
> >
> >                           The question is, is this how it's supposed to
> >         be done
> >                  via the spec?
> >
> >                           Implementation wise, what happens in Weld is
> >         that the
> >                  CDI/EJB proxy
> >                           (com.test.Foo$Proxy$_$$_Weld$EnterpriseProxy$)
> >         in the
> >                  following code
> >                           doesn't hit the check for a dependent instance
> >                  (comments in capitals
> >                           added by me):
> >
> >
> >                                 public void destroy(T instance) {
> >                                     Preconditions.checkNotNull(instance);
> >
> >                                     // check if this is a proxy of a
> >                  normal-scoped bean
> >                                     if (instance instanceof ProxyObject)
> {
> >
> >                                         // THIS BRANCH IS TAKEN FOR
> >         CDI/EJB PROXY
> >
> >                                         ProxyObject proxy =
> >         (ProxyObject) instance;
> >                                         if (proxy.getHandler() instanceof
> >                           ProxyMethodHandler) {
> >                                             ProxyMethodHandler handler =
> >                  (ProxyMethodHandler)
> >                           proxy.getHandler();
> >                                             Bean<?> bean =
> >         handler.getBean();
> >                                             Context context =
> >                           getBeanManager().getContext(bean.getScope());
> >                                             if (context instanceof
> >                  AlterableContext) {
> >                                                 AlterableContext
> >         alterableContext =
> >                           (AlterableContext) context;
> >
> >                                                 // CONTEXT IS A
> >                  DEPENDENTCONTEXTIMPL THAT
> >                           THROWS
> >                                                 //
> >         UnsupportedOperationException
> >                  FROM ITS
> >                           DESTROY()
> >                           METHOD
> >
> >           alterableContext.destroy(bean);
> >                                                 return;
> >                                             } else {
> >                                                 throw
> >                           BeanLogger.LOG.destroyUnsupported(context);
> >                                             }
> >                                         }
> >                                     }
> >
> >                                     // check if this is a dependent
> instance
> >                                     CreationalContext<? super T> ctx =
> >                  getCreationalContext();
> >                                     if (ctx instanceof
> >         WeldCreationalContext<?>) {
> >                                         WeldCreationalContext<? super T>
> >         weldCtx
> >                  = cast(ctx);
> >
> >                                         // PROXY REFERENCES ARE KEPT
> >         HERE IN A
> >                                         // "dependentInstances" LIST,
> >         AND WOULD
> >                  BE CLEARED
> >                           HERE
> >                                         // BUT THIS CODE IS NEVER REACHED
> >
> >           weldCtx.destroyDependentInstance(instance);
> >                                     }
> >                                 }
> >
> >                           Now I wonder, am I doing something wrong
> >         (according to
> >                  the CDI
> >                           spec), or
> >                           could this be a bug in the Weld code?
> >
> >                           Kind regards,
> >                           Arjan Tijms
> >
> >
> >                           _______________________________________________
> >                           cdi-dev mailing list
> >         cdi-dev at lists.jboss.org <mailto:cdi-dev at lists.jboss.org>
> >         <mailto:cdi-dev at lists.jboss.org <mailto:cdi-dev at lists.jboss.org
> >>
> >                  <mailto:cdi-dev at lists.jboss.org
> >         <mailto:cdi-dev at lists.jboss.org> <mailto:cdi-dev at lists.jboss.org
> >         <mailto:cdi-dev at lists.jboss.org>>>
> >         https://lists.jboss.org/mailman/listinfo/cdi-dev
> >
> >                           Note that for all code provided on this list,
> >         the provider
> >                           licenses the code under the Apache License,
> >         Version 2
> >
> >           (http://www.apache.org/licenses/LICENSE-2.0.html). For
> >                  all other
> >                           ideas provided on this list, the provider
> >         waives all
> >                  patent and
> >                           other intellectual property rights inherent in
> >         such
> >                  information.
> >
> >
> >                       --
> >                       Martin Kouba
> >                       Software Engineer
> >                       Red Hat, Czech Republic
> >
> >
> >
> >              --
> >              Martin Kouba
> >              Software Engineer
> >              Red Hat, Czech Republic
> >
> >
> >
> >     --
> >     Martin Kouba
> >     Software Engineer
> >     Red Hat, Czech Republic
> >
> >
>
> --
> Martin Kouba
> Software Engineer
> Red Hat, Czech Republic
> _______________________________________________
> cdi-dev mailing list
> cdi-dev at lists.jboss.org
> https://lists.jboss.org/mailman/listinfo/cdi-dev
>
> Note that for all code provided on this list, the provider licenses the
> code under the Apache License, Version 2 (
> http://www.apache.org/licenses/LICENSE-2.0.html). For all other ideas
> provided on this list, the provider waives all patent and other
> intellectual property rights inherent in such information.
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: http://lists.jboss.org/pipermail/cdi-dev/attachments/20160512/0eae9af6/attachment-0001.html 


More information about the cdi-dev mailing list