[cdi-dev] Proxy implementation leaks
Mark Struberg
struberg at yahoo.de
Tue May 24 15:42:57 EDT 2011
Imo it is surprising, since it would break all kinds of 'business injections' (as opposed to classic 'resource injections' - Jens Schumann can explain this well ;)
I think 5.4.2. Client proxy invocation + 6.5.2. Contextual instance of a bean goes rather in the direction of _very_ lazy initialization ;)
Imho, the current behaviour of Weld, OWB and CanDI is correct.
LieGrue,
strub
--- On Tue, 5/24/11, Pete Muir <pmuir at redhat.com> wrote:
> From: Pete Muir <pmuir at redhat.com>
> Subject: Re: [cdi-dev] Proxy implementation leaks
> To: "Mark Struberg" <struberg at yahoo.de>
> Cc: cdi-dev at lists.jboss.org
> Date: Tuesday, May 24, 2011, 7:24 PM
>
> On 24 May 2011, at 20:15, Mark Struberg wrote:
>
> >> Don't quite get this, spec requires that contexts
> are
> >> active only at particular points.
> >
> > yes but imagine the following
> >
> > @ApplicationScoped
> > public class MyService {
> > private @Inject User usr; /* User is RequestScoped */
> >
> > ...
> > }
> >
> > and this MyService will first get invoked in an EJB
> which gets initialized at startup. At this time there is NO
> Request Context active!
> > Thus if you would require all contextual instances
> being created immediately, then you would get a
> ContextNotActiveException...
>
> Yes, but this isn't that surprising and the principle of
> least surprise is a good one to follow ;-)
>
> >
> > LieGrue,
> > strub
> >
> > --- On Tue, 5/24/11, Pete Muir <pmuir at redhat.com>
> wrote:
> >
> >> From: Pete Muir <pmuir at redhat.com>
> >> Subject: Re: [cdi-dev] Proxy implementation leaks
> >> To: "Mark Struberg" <struberg at yahoo.de>
> >> Cc: cdi-dev at lists.jboss.org
> >> Date: Tuesday, May 24, 2011, 7:10 PM
> >>
> >> On 24 May 2011, at 19:38, Mark Struberg wrote:
> >>
> >>> Doing this in 2 phases is exactly what I mean
> with
> >> lazy initialisation. For the cyclic injection
> prevention it
> >> doesn't matter _how_ lazy.
> >>>
> >>> As you said: without splitting the proxy
> creation from
> >> the contextual instance creation, we would not be
> able to do
> >> proper cyclic injection. For this to work this
> must be a 2
> >> staged process. Like with forward references in
> compilers.
> >>
> >> Yes, however we can require that this is all done
> by a
> >> certain point.
> >>
> >>> Of course the current _very_ lazy behaviour
> might lead
> >> to curious situations sometimes (as in my
> example). But the
> >> 'eager' mechanism might lead to 'Context not
> active'
> >> Exceptions if you e.g. have a @RequestScoped field
> which
> >> isn't even touched when an @ApllicationScoped
> reference gets
> >> created in an asynchronous EJB. So you can decide
> between
> >> bad and evil ;)
> >>
> >> Don't quite get this, spec requires that contexts
> are
> >> active only at particular points.
> >>
> >>>
> >>> LieGrue,
> >>> strub
> >>>
> >>> --- On Tue, 5/24/11, Pete Muir <pmuir at redhat.com>
> >> wrote:
> >>>
> >>>> From: Pete Muir <pmuir at redhat.com>
> >>>> Subject: Re: [cdi-dev] Proxy
> implementation leaks
> >>>> To: "Pete Muir" <pmuir at redhat.com>
> >>>> Cc: "Mark Struberg" <struberg at yahoo.de>,
> >> cdi-dev at lists.jboss.org
> >>>> Date: Tuesday, May 24, 2011, 5:47 PM
> >>>> On reflection, I don't believe this
> >>>> is correct. The lazy init doesn't help
> with
> >> cyclic
> >>>> injection, it is simply the presence of
> proxies
> >> that does
> >>>> this.
> >>>>
> >>>> Consider that the DI graph is created
> using
> >> proxies, and
> >>>> call this phase 1. Weld currently does
> phase 1 on
> >>>> injection.
> >>>>
> >>>> Phase 2 is the actual instantiation of the
> objects
> >> backing
> >>>> this graph. Weld currently does phase 2
> lazily,
> >> when the
> >>>> first method on a proxy is called and
> needs to be
> >> passed to
> >>>> the bean (and this repeats through the
> graph).
> >>>>
> >>>> We need to split this into two phases, but
> there
> >> is no
> >>>> reason that we can't require
> implementations to do
> >> phase 2
> >>>> immediately that phase 1 has completed,
> before we
> >> give
> >>>> control to client code.
> >>>>
> >>>> On 9 May 2011, at 16:19, Pete Muir wrote:
> >>>>
> >>>>> Thanks Mark, I knew there was a reason
> for the
> >> lazy
> >>>> init.
> >>>>>
> >>>>> The two-ctor call is not necessary
> though.
> >>>>>
> >>>>> On 9 May 2011, at 16:15, Mark Struberg
> wrote:
> >>>>>
> >>>>>> actually this behaviour is pretty
> clear in
> >> EE.
> >>>> It's the same thing as we have with EJBs
> since
> >> almost ever.
> >>>> That's why @PostConstruct exists.
> >>>>>>
> >>>>>> Whenever object proxies or
> >> hidden/transparent
> >>>> serialisation happens, then we need to
> create the
> >>>> object/proxy on the other side/new
> invocation. And
> >> everytime
> >>>> this happens, the constructer will
> obviously get
> >> called.
> >>>>>>
> >>>>>> So this is not a bug and surely
> not a
> >> leak!
> >>>>>>
> >>>>>> This was on our list when I did a
> talk
> >> about CDI
> >>>> pitfalls at the JSFdays last year together
> with
> >> Dan.
> >>>>>>
> >>>>>> Maybe we should doument this
> better, but
> >> it's
> >>>> nothing for the spec, but the user
> documentation
> >> imo.
> >>>>>>
> >>>>>> Also the lazy init is imo a well
> specified
> >> and
> >>>> welcome behaviour. Look at the discussions
> way
> >> back about
> >>>> how to prevent cyclic injection problems.
> >>>>>>
> >>>>>> LieGrue,
> >>>>>> strub
> >>>>>>
> >>>>>> --- On Mon, 5/9/11, Christian
> Bauer <christian.bauer at gmail.com>
> >>>> wrote:
> >>>>>>
> >>>>>>> From: Christian Bauer <christian.bauer at gmail.com>
> >>>>>>> Subject: [cdi-dev] Proxy
> >> implementation leaks
> >>>>>>> To: cdi-dev at lists.jboss.org
> >>>>>>> Date: Monday, May 9, 2011,
> 2:46 PM
> >>>>>>> Started working with Weld
> 1.1.1 and
> >>>>>>> found two issues that probably
> should
> >> be
> >>>> addressed (maybe
> >>>>>>> just documented). They both
> look to me
> >> like
> >>>> leaking
> >>>>>>> implementation details because
> proxies
> >> are
> >>>> used for
> >>>>>>> components which are not
> @Singleton
> >> or
> >>>> @Dependent.
> >>>>>>>
> >>>>>>> @ApplicationScoped
> >>>>>>> public class Bug {
> >>>>>>>
> >>>>>>> public
> Bug() {
> >>>>>>>
> >>>>>>>
> >> System.out.println("##########
> >>>>>>> CONSTRUCT");
> >>>>>>> }
> >>>>>>>
> >>>>>>> public
> void foo() {
> >>>>>>>
> >>>>
> System.out.println("#####
> >>>>>>> FOO");
> >>>>>>> }
> >>>>>>>
> >>>>>>> public
> static void
> >>>> main(String[] args) {
> >>>>>>>
> Weld weld =
> >> new
> >>>> Weld();
> >>>>>>>
> >> WeldContainer
> >>>> weldContainer
> >>>>>>> = weld.initialize();
> >>>>>>>
> >>>>>>>
> Bug bug =
> >>>>>>>
> >>>>
> weldContainer.instance().select(Bug.class).get();
> >> //
> >>>> Creates
> >>>>>>> new instance of Bug
> >>>>>>>
> bug.foo();
> >> //
> >>>> Creates new
> >>>>>>> instance of Bug!!!
> >>>>>>>
> bug.foo();
> >> //
> >>>> Uses existing
> >>>>>>> instance
> >>>>>>>
> >>>>>>>
> >>>> weld.shutdown();
> >>>>>>> }
> >>>>>>> }
> >>>>>>>
> >>>>>>> The proxy of Bug will call
> its
> >> superclass
> >>>> constructor
> >>>>>>> several times during the
> lifecycle of
> >> the Bug
> >>>> component. I
> >>>>>>> don't know if that is really
> >> necessary, but if
> >>>> it is, you
> >>>>>>> can now no longer use
> constructors to
> >>>> initialize your
> >>>>>>> component. This is an issue
> because
> >>>>>>>
> >>>>>>> - it's not documented that
> >> constructors of
> >>>>>>> @ApplciationScoped (etc.,
> proxied)
> >> components
> >>>> behave
> >>>>>>> differently than
> >> @Singleton/@Dependent
> >>>> constructors
> >>>>>>>
> >>>>>>> - even if it's documented,
> it's
> >> questionable
> >>>> if that really
> >>>>>>> should be the case.
> >>>>>>>
> >>>>>>> Taking away constructors as
> the
> >> primary means
> >>>> of
> >>>>>>> initializing a component -
> e.g.
> >> obtaining
> >>>> resources such as
> >>>>>>> database connections, reading
> config
> >> files,
> >>>> etc. - is a
> >>>>>>> major change in the Java
> programming
> >> model.
> >>>> Users have to be
> >>>>>>> strongly advised to use
> @PostConstruct
> >> then.
> >>>>>>>
> >>>>>>> The other issue I immediately
> found is
> >> also
> >>>> related to
> >>>>>>> behavior of proxies and how
> >> transitive
> >>>>>>> initializing/injection is
> implemented
> >> (not
> >>>> sure if this is
> >>>>>>> actually specified
> somewhere):
> >>>>>>>
> >>>>>>> @ApplicationScoped
> >>>>>>> public class Foo {
> >>>>>>>
> >>>>>>>
> @Inject
> >>>>>>> Bar
> bar;
> >>>>>>>
> >>>>>>> }
> >>>>>>>
> >>>>>>> @ApplicationScoped
> >>>>>>> public class Bar {
> >>>>>>>
> >>>>>>> @Inject
> >>>>>>> Baz baz;
> >>>>>>>
> >>>>>>>
> >> @PostConstruct
> >>>>>>> void
> init() {
> >> ... }
> >>>>>>>
> >>>>>>> }
> >>>>>>>
> >>>>>>> When I obtain a reference to
> Foo, I
> >> get a
> >>>> proxy of Foo with
> >>>>>>> a reference to a proxy of Bar.
> The
> >> init()
> >>>> method of Bar is
> >>>>>>> never called. The Baz
> component is
> >> never
> >>>> activated.
> >>>>>>>
> >>>>>>> This means I can't
> transitively
> >> initialize an
> >>>>>>> application-scoped graph of
> >> components. I was
> >>>> trying to use
> >>>>>>> CDI for wiring in a Swing
> application
> >> and I
> >>>> imagine this
> >>>>>>> would be a common usecase. It
> should
> >> either be
> >>>> documented
> >>>>>>> that there is a difference
> between
> >>>> @Singleton/@Dependent and
> >>>>>>> proxy-implemented scopes, or
> >> unification
> >>>> should be
> >>>>>>> considered.
> >>>>>>>
> >>
> >>
>
>
More information about the cdi-dev
mailing list