[cdi-dev] Proxy implementation leaks

Pete Muir pmuir at redhat.com
Tue May 24 15:10:36 EDT 2011


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