A number of people have been asking how to create a custom scope, so I wanted to write a short guide. Unfortunately there isn't a universal solution, so the best I can do is offer up a number of guidelines and give you some questions to consider before embarking on the implementation.
Before you begin, read the Javadoc for Context, the interface you will be implementing.
The first thing to consider when implementing a context is what you will use to store the bean instances. If you want to share the bean instances between multiple
requests (such as the HTTP session scope) then you will need a way to store the bean instances and to associate the correct set of bean instances with the current
request. If you want to simply share the bean instances within the
request then you have an easier task, as you can use a ThreadLocal to store the bean instances, and just remove it at the end of the
Note that when I say
request I mean any request to the application, not just an HTTP request. CDI doesn't give you any help here, but for inspiration you can think about the built in HTTP contexts such as the session context which uses the HttpSession from the Servlet specification to store the bean instances, and request listeners to associate the context with the bean instances at the start of each request.
Having decided on where the bean instances will be stored, you need to think about how to associate the bean instance store with the context at the start of each
request, and how to clean up at the end of the
request. Luckily, there is a standard formula you can follow here! Within your context, use a ThreadLocal to hold the bean instances for the duration of the
request; the lifecycle of the context would look something like this:
- At the start of the
requestassociate the bean instance store with the context by storing it in the thread local
- During the
requestservice any calls to Context.get() using the ThreadLocal
- At the end of the request ensure that you clean up the ThreadLocal to prevent any memory leaks
There is a variant of this, where the bean instance store used during the
request does not write through to the underlying bean instance store, but is instead synchronised (e.g. last
request to end wins) at the end of the
request. This has the advantage of improving the apparent consistency of the data (consider multiple concurrent requests, if you write through to the underlying store the state at the end of the request could be a mix of that written in each request), as well as allowing for lazy-creation of the underlying store. This is also relatively simple to implement, the only complex part being the decision on synchronization scheme to use.
Once you have implemented your context, you need to register it, which you do via AfterBeanDiscovery.addContext.
I hope this is of use to people, and if anyone has other useful tips and hints, please do comment on the blog, and I will update it!