I am struggling to understand the effective lifecycle of a @Dependent
scoped bean in both CDI 1.0 and CDI 1.1. My experiments so far have lead me to the following conclusions:
@Dependent
scoped bean is not proxied.@PreDestroy
method is invoked when a @Dependent
bean is destroyed.Provider.get()
always creates a new instance of a @Dependent
bean.@Dependent
bean that is created by an @ApplicationScoped
bean's Provider<>
field is "leaked", because it still "belongs" to the Provider
.@Dependent
beans being leaked by similar Provider
s when using WELD 2.1.2.Final/CDI 1.1. (Although this might be because these particular @Dependent
beans are created by @Produces
methods...!)I see that CDI 1.1 has added a destroy()
method to Instance<>
, presumably to address the memory leak in CDI 1.0. But what about Provider<>
- does that still leak in CDI 1.1? (And if it does, then how are you supposed to use Provider.get()
?)
Basically, I have several @ApplicationScoped
beans / @Singleton
EJBs that I @Inject
Provider
fields into, and I am trying to use Provider.get()
as factories for both @Dependent
and @RequestScoped
"helper" beans. I definitely do not want these beans to "belong" to their Provider
fields, as I need the beans to be garbage collected afterwards:
public void updateStuff() {
Helper helper = helperProvider.get();
// use helper...
}
For my CDI 1.0 application, I was thinking of fixing the memory leak by "faking" my Provider
s with code like this:
provider = new Provider<MyBean>() {
@Override
public MyBean get() {
return getReferenceFor(MyBean.class);
}
};
private <T> T getReferenceFor(Class<T> type) {
Bean<?> bean = beanManager.resolve(beanManager.getBeans(type));
CreationalContext<?> context = beanManager.createCreationalContext(bean);
try {
return (T) beanManager.getReference(bean, bean.getBeanClass(), context);
} finally {
// Destroy this context - which I don't want to exist anyway.
// I only need a strong reference to a fully @Inject-ed bean!
context.release();
}
}
MyBean
is a @Dependent
scoped bean with no @PreDestroy
method that only needs to be garbage collected when I've finished with it. However, I can't find a lot of information about Provider
s, and so can't tell if I'm arming some kind of time-bomb by doing this.
Some of my @Dependent
scoped beans (which I still obtain via Provider.get()
, btw) are created by @Produces
methods. Are they still in danger of being leaked?
Can anyone advise me, please?
Thanks,
Chris
From Weld docs on lifecycle of @Dependent beans:
An instance of a dependent bean is never shared between different clients or different injection points. It is strictly a dependent object of some other object. It is instantiated when the object it belongs to is created, and destroyed when the object it belongs to is destroyed.
So injection of @Dependent object won't introduce a leak on its own, there's simply nothing to fix.
Creating a short-lived context just "to be on the safe side" is totally unnecessary because
dependent beans aren't tied to a context. As far as CDI is concerned after being injected they are ordinary (strongly reachable) Java objects.
If you need instantiation logic put it in a producer method and that's it.