The MicroProfile Context Propagation spec defines a fluent builder API to programmatically obtain instances of ManagedExecutor
and ThreadContext
. Builder instances are obtained via static builder()
methods on ManagedExecutor
and ThreadContext
.
import java.util.concurrent.CompletionStage;
import java.util.concurrent.CompletableFuture;
import javax.servlet.ServletConfig;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.eclipse.microprofile.context.ManagedExecutor;
import org.eclipse.microprofile.context.ThreadContext;
public class ExampleServlet extends HttpServlet {
ManagedExecutor executor;
public void init(ServletConfig config) {
executor = ManagedExecutor.builder()
.propagated(ThreadContext.APPLICATION)
.cleared(ThreadContext.ALL_REMAINING)
.maxAsync(5)
.build();
}
public void doGet(HttpServletRequest req, HttpServletResponse res) {
completionStage = executor.runAsync(task1)
.thenRunAsync(task2)
...
}
public void destroy() {
executor.shutdown();
}
}
Applications are encouraged to cache and reuse ManagedExecutor
instances.
It is the responsibility of the application to shut down ManagedExecutor
instances that are no longer needed, so as to allow the container to
efficiently free up resources.
import java.util.concurrent.CompletableFuture;
import java.util.function.Function;
import java.util.function.Supplier;
import javax.servlet.ServletConfig;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.eclipse.microprofile.context.ThreadContext;
public class ExampleServlet extends HttpServlet {
ThreadContext threadContext;
public void init(ServletConfig config) {
threadContext = ThreadContext.builder()
.propagated(ThreadContext.APPLICATION, ThreadContext.SECURITY)
.unchanged()
.cleared(ThreadContext.ALL_REMAINING)
.build();
}
public void doGet(HttpServletRequest req, HttpServletResponse res) {
Function<Long, Long> contextFn = threadContext.contextualFunction(x -> {
... operation that requires security & application context
return result;
});
// By using java.util.concurrent.CompletableFuture.supplyAsync rather
// than a managed executor, context propagation is unpredictable,
// except for the contextFn action that we pre-contextualized using
// ThreadContext above.
stage = CompletableFuture.supplyAsync(supplier)
.thenApplyAsync(function1)
.thenApply(contextFn)
...
}
}
Instances of ManagedExecutor.Builder
and ThreadContext.Builder
retain their configuration after the build method is
invoked and can be reused. Subsequent invocations of the build() method create new instances of
ManagedExecutor
and ThreadContext
that operate independently of previously built instances.