[cdi-dev] Proxy implementation leaks

Pete Muir pmuir at redhat.com
Tue May 24 13:47:14 EDT 2011


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.
>>> 
>>> 
>>> _______________________________________________
>>> cdi-dev mailing list
>>> cdi-dev at lists.jboss.org
>>> https://lists.jboss.org/mailman/listinfo/cdi-dev
>>> 
> 
> 
> _______________________________________________
> cdi-dev mailing list
> cdi-dev at lists.jboss.org
> https://lists.jboss.org/mailman/listinfo/cdi-dev




More information about the cdi-dev mailing list