[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