[cdi-dev] Proxy implementation leaks
Pete Muir
pmuir at redhat.com
Tue May 24 15:24:13 EDT 2011
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