The specification of JEE defines, that only the ApplicationScope
and DependentScope
have to be activated within an executed thread (managed or non-managed). Hence, by executing asynchronous processes by ExecutorService.submit(process)
, an error is thrown because RequestContext
is inactive, if RequestScoped
beans are injected, used or produced anywhere during invocation.
Now it could be the case, that you have a CDI-producer which produces a RequestScope
bean, e.g. as a result of an incoming CDI event. Instead of creating a custom scope, like ThreadScoped
or something, it’s more straightforward and much more easier to activate the RequestContext
in your executor process.
The drawback here is, that this is a CDI-implementation specific feature, because the RequestContext itself is not part of the standardized CDI-API. In practice, this isn’t really a problem, since the most (all?) containers are working with WELD as CDI implementation.
Since we know the theory now, let the code speak:
import org.jboss.weld.context.bound.BoundRequestContext; public class Processor { @Inject private ExecutorService executor; @Inject private BoundRequestContext requestContext; public void doit(Runnable command) { Future<?> future = executor.submit(() -> { // activate RequestContext for this thread requestContext.associate(Maps.newHashMap()); requestContext.activate(); try { // execute the command command.run(); } finally { // destroy context in any case (memory cleanup) requestContext.deactivate(); } }); // analyze future if necessary } }
BoundRequestContext
is a WELD interface. The RequestContext
is bound to the executed thread (due use of ThreadLocal
). Hence, two concurrently invocations of doit()
don’t influence each other. Each thread will get it’s own context-map, since we associate the context with a new HashMap
before the real command is triggered.