[cdi-dev] Proxy implementation leaks
Pete Muir
pmuir at redhat.com
Tue May 24 15:46:52 EDT 2011
On 24 May 2011, at 20:42, Mark Struberg wrote:
> 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 ;)
Can you make him explain it for our edification?
>
> 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 ;)
Well we can leave it explicitly unspecified should we wish (i.e. we make it unportable). This reserves the right to change our mind later.
> 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