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

Martin Kouba mkouba at redhat.com
Wed May 11 07:04:56 EDT 2016


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();
}

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


More information about the cdi-dev mailing list