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.
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 ;)
LieGrue,
strub
--- On Tue, 5/24/11, Pete Muir <pmuir(a)redhat.com> wrote:
From: Pete Muir <pmuir(a)redhat.com>
Subject: Re: [cdi-dev] Proxy implementation leaks
To: "Pete Muir" <pmuir(a)redhat.com>
Cc: "Mark Struberg" <struberg(a)yahoo.de>, cdi-dev(a)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(a)gmail.com>
wrote:
>>
>>> From: Christian Bauer <christian.bauer(a)gmail.com>
>>> Subject: [cdi-dev] Proxy implementation leaks
>>> To: cdi-dev(a)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.
>>>