Is it possible to destroy a CDI scope?
Asked Answered
N

4

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?
Niedersachsen answered 23/6, 2011 at 19:16 Comment(3)
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?Cranwell
That's not going to fly for this app. I'm not just using DI because it's shiny.Niedersachsen
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)Shanna
C
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

Charin answered 3/7, 2011 at 22:48 Comment(2)
@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.Charin
Thanks for the information! I will definitely try out this (non-portable) method when I have a chance.Niedersachsen
E
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.

Endocardial answered 30/8, 2011 at 2:17 Comment(2)
This might do quite nicely... I assume you're specifically talking about DestroyableContext?Niedersachsen
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.Endocardial
C
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.

Cristen answered 30/6, 2011 at 20:35 Comment(1)
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...Niedersachsen
S
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:

Slashing answered 16/6, 2014 at 11:45 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.