CDI Custom Scope

In this post i will show how to create a custom CDI scope by performing the following steps:

  1. register the scope in a CDI Extension
  2. manage the scope through a CDI context
  3. show how to store and keep custom scoped beans ‘alive’
  4. ‘kill’ custom beans through CDI events

Check the source code of this entry at:
also you can see a video produced by this blog entry code here

First of all lets talk about CDI scopes, which are responsible by the lifecycle of CDI beans. Every scope is bound to a CDI context[1] which in turn manages the scope and states when the scope is active and passive. The context also holds all instances of the beans associated to the scope it manages.

For example the built in RequestScope is bound to a http request, the RequestContext must ensure that all beans in this scope will be alive during a http request and be passivated at the end of it, you can see weld http based contexts in [4].

Creating the Custom Scope

We will create a CDI Custom Scope which will be activated when a bean in this scope is referenced through EL and or injected in another bean and it will ‘die’ when a specific CDI event is fired.

First thing to do is create an annotation which will represent our scope:

public @interface MyScope {}

Now we add our scope and register the context that will manage it  in a CDI extension:

public class CustomScopeExtension implements Extension, Serializable {
    public void addScope(@Observes final BeforeBeanDiscovery event) {
        event.addScope(MyScope.class, true, false);
    public void registerContext(@Observes final AfterBeanDiscovery event) {
        event.addContext(new CustomScopeContext());

All the logic of our scope is in the CustomScopeContext class:

public class CustomScopeContext implements Context, Serializable {

    private Logger log = Logger.getLogger(getClass().getSimpleName());

    private CustomScopeContextHolder customScopeContextHolder;

    public CustomScopeContext() {"Init");
        this.customScopeContextHolder = CustomScopeContextHolder.getInstance();

    public <T> T get(final Contextual<T> contextual) {
        Bean bean = (Bean) contextual;
        if (customScopeContextHolder.getBeans().containsKey(bean.getBeanClass())) {
            return (T) customScopeContextHolder.getBean(bean.getBeanClass()).instance;
        } else {
            return null;

    public <T> T get(final Contextual<T> contextual, final CreationalContext<T> creationalContext) {
        Bean bean = (Bean) contextual;
        if (customScopeContextHolder.getBeans().containsKey(bean.getBeanClass())) {
            return (T) customScopeContextHolder.getBean(bean.getBeanClass()).instance;
        } else {
            T t = (T) bean.create(creationalContext);
            CustomScopeInstance customInstance = new CustomScopeInstance();
            customInstance.bean = bean;
            customInstance.ctx = creationalContext;
            customInstance.instance = t;
            return t;

    public Class<? extends Annotation> getScope() {
        return MyScope.class;

    public boolean isActive() {
        return true;

    public void destroy(@Observes KillEvent killEvent) {
        if (customScopeContextHolder.getBeans().containsKey(killEvent.getBeanType())) {

The Mandatory methods you must implement are getScope() which must return the qualifier bound to this scope, two get() implementaions that i will talk later and isActive() which states when the scope should be taken into account, for example Seam3 viewScope[5] is active only when viewRoot is rendered.

The idea behind the context is that its GET methods will be called every time a bean associated with the context is injected in or is referenced though expression language in a page.  The GET with CreationalContext  parammeter will be called only the first time the bean is referenced so it can be created.

Every time a bean is referenced the context will look in customScopeContextHolder to verify if the bean is already created, in positive case  it will return the instance otherwise it will create one and add into the list of beans managed by customScopeContextHolder which is a singleton class that holds the list of CDI beans associated with our custom scope, note that you might create your own logic to hold your context’s beans. Also note that our context is observing a CDI event to remove beans from the context which is another important thing you must take care when creating your own scope, see destroy method.

Below is the bean ContextHolder code:

public class CustomScopeContextHolder implements Serializable {

    private static CustomScopeContextHolder INSTANCE;
    private Map<Class, CustomScopeInstance> beans;//we will have only one instance of a type so the key is a class

    private CustomScopeContextHolder() {
        beans = Collections.synchronizedMap(new HashMap<Class, CustomScopeInstance>());

    public synchronized static CustomScopeContextHolder getInstance() {
        if (INSTANCE == null) {
            INSTANCE = new CustomScopeContextHolder();
        return INSTANCE;

    public Map<Class, CustomScopeInstance> getBeans() {
        return beans;

    public CustomScopeInstance getBean(Class type) {
        return getBeans().get(type);

    public void putBean(CustomScopeInstance customInstance) {
        getBeans().put(customInstance.bean.getBeanClass(), customInstance);

    void destroyBean(CustomScopeInstance customScopeInstance) {
        customScopeInstance.bean.destroy(customScopeInstance.instance, customScopeInstance.ctx);

* wrap necessary properties so we can destroy the bean later:
* @see
* CustomScopeContextHolder#destroyBean(custom.scope.extension.CustomScopeContextHolder.CustomScopeInstance)
    public static class CustomScopeInstance<T> {

        Bean<T> bean;
        CreationalContext<T> ctx;
        T instance;

Holding bean references

Note that CustomScopeContext is a normal java class, it is instantiated via new operator, so it is not a good ideia storing our bean references in it because CDI will instantiate it as it needs losing the bean instances stored in it(see Martin’s comment). For example when a bean(in our context) participate on a CDI event the CDI container will create a thread of the context to attend the event so because of this we introduced the CustomScopeContextHolder to manage our bean instances. There are other approaches such as ThreadLocals[6], http session, JSF viewroot[5], static variables etc… I decided to use a singleton something like Deltaspike TransactionContext[7] but faraway simpler.


We saw here a powerful mechanism provided by CDI to manage our beans lifecycle. In 90% of the cases the built in scopes will be sufficient but having the hability to extend the plataform to allow things such as CODI scopes[8] or Jaxb objects handled by a CDI scope[9][10] is priceless.

Now to use our scope we just declare a bean with @MyScope and inject it in another bean, to see the CustomScope in action visit: or clone the code at