10

I'm working on a Java EE application, primarily JAX-RS with a JSF admin console, that uses CDI/Weld for dependency injection with javax.enterprise.context.ApplicationScoped objects. Minor debugging issues aside, CDI has worked beautifully for this project.

Now I need some very coarse-grained control over CDI-injected object lifecycles. I need the ability to:

  • Remove an injected object from the application context, or
  • Destroy/delete/clear/reset/remove the entire application context, or
  • Define my own @ScopeType and implementing Context in which I could provide methods to perform one of the two above tasks.

I'm fully aware that this is across, if not against, the grain of CDI and dependency injection in general. I just want to know

  • Is this remotely possible?
  • If yes, what is the easiest/simplest/quickest/foolproofiest way to get the job done?
Matt Ball
  • 354,903
  • 100
  • 647
  • 710
  • just curious: what if these objects are simply global objects, i.e. some static fields. No DI is involved. In your specific application, can you attest that DI is really valuable for you app scope objects? – irreputable Jun 23 '11 at 23:49
  • 1
    That's not going to fly for this app. I'm not just using DI because it's shiny. – Matt Ball Jun 24 '11 at 05:44
  • I don't think this goes against the grain of DI at all - after all, the CDI specification was created to address precisely the matter of scope lifecycle, and explicitly allows the creation of new scopes (Granted, recreating a particular bean in a context is not the CDI way) – meriton Jun 30 '11 at 21:15

4 Answers4

5

Weld Reference Documentation Section 2.1.2

Keep in mind that once a bean is bound to a context, it remains in that context until the context is destroyed. There is no way to manually remove a bean from a context. If you don't want the bean to sit in the session indefinitely, consider using another scope with a shorted lifespan, such as the request or conversation scope.

Custom scope example Porting the veiwscoped jsf annonation to cdi

If you really don't want to take the path of the Custom scope type.. You can use a non-portable method by using BeanManager.getContext method and cast this context in a weld AbstractSharedContext to have access to the beanstore or the cleanUp() method of the context.

Check this thread on how to get a BeanManager instance for your environment

Joel Hudon
  • 3,145
  • 1
  • 20
  • 13
  • @Matt Ball Sorry didn't see you did not really want to go in the Custom scope type,so i edit the answer to add another possible solution i can see. – Joel Hudon Jul 04 '11 at 16:14
  • Thanks for the information! I will definitely try out this (non-portable) method when I have a chance. – Matt Ball Jul 04 '11 at 23:29
4

A custom scope which might fit your needs is available at https://github.com/openknowledge/openknowledge-cdi-extensions/tree/master/openknowledge-cdi-scope/src/main/java/de/openknowledge/cdi/scope Maybe you have to adjust the implementation a bit.

Dar Whi
  • 822
  • 5
  • 14
  • This might do quite nicely... I assume you're specifically talking about `DestroyableContext`? – Matt Ball Aug 30 '11 at 02:18
  • Yes. It's at least very similar. You could also have a look at the JSF centric scopes of MyFaces CODI which are also fine grained, but if you need something independent of JSF and/or easy to use as template for your custom scope, that one might fit. – Dar Whi Aug 30 '11 at 02:23
1

In CDI 1.1 there is a javax.enterprise.context.spi.AlterableContext interface, which allows you to individually destroy a bean instance. All normal scopes (request, conversation, session) are alterable.

AlterableContext ctxConversation = (AlterableContext) beanManager.getContext(ConversationScoped.class);
for (Bean<?> bean : beanManager.getBeans(Object.class)) {
    Object instance = ctxConversation.get(bean);
    if (instance != null) {
        ctxConversation.destroy(instance);
    }
}

The beanManager here is a javax.enterprise.inject.spi.BeanManager instance. You can get it via JNDI lookup:

InitialContext.doLookup("java:comp/BeanManager");

or via CDI static method:

CDI.current().getBeanManager();

, but be aware of the issues with the static method in some Weld versions:

Vsevolod Golovanov
  • 4,068
  • 3
  • 31
  • 65
1

Out of the box there is only the Conversation scope that gives you total control on its lifecycle. But you can create your own scope if conversation doesn't suit your needs. Creating a scope is a tough job, but you can go to weld code and look how conversation was implemented.

Antoine Sabot-Durand
  • 4,875
  • 17
  • 33
  • I did try to use conversation scope already - unfortunately my brief attempt was not fruitful. It does look like a custom scope is the only solution, though I'd really rather not take this path... – Matt Ball Jun 30 '11 at 21:00