This section includes some additional examples of spec usage.
executor = ManagedExecutor.builder()
.cleared(ThreadContext.TRANSACTION, ThreadContext.SECURITY)
.propagated(ThreadContext.ALL_REMAINING)
.build();
CompletableFuture<Long> stage1 = executor.newIncompleteFuture();
stage1.thenApply(function1) // runs with captured context
.thenApply(function2); // runs with captured context
stage1.completeAsync(supplier1); // runs with captured context
threadContext = ThreadContext.builder()
.propagated(ThreadContext.SECURITY)
.unchanged()
.cleared(ThreadContext.ALL_REMAINING)
.build();
stage = threadContext.withContextCapture(invokeSomeMethodThatReturnsUnmanagedCompletionStage());
stage.thenApply(function1) // runs with captured context
.thenAccept(consumer); // runs with captured context
threadContext = ThreadContext.builder()
.propagated(ThreadContext.SECURITY)
.unchanged()
.cleared(ThreadContext.ALL_REMAINING)
.build();
Consumer<String> contextualConsumer = threadContext.contextualConsumer(s -> {
... do something that requires context
});
stage = invokeSomeMethodThatReturnsUnmanagedCompletionStage();
stage.thenApply(function1) // context is unpredictable
.thenAccept(contextualConsumer); // runs with captured context
threadContext = ThreadContext.builder()
.cleared(ThreadContext.TRANSACTION)
.unchanged(ThreadContext.SECURITY)
.propagated(ThreadContext.ALL_REMAINING)
.build();
contextSnapshot = threadContext.currentContextExecutor();
... on some other thread,
contextSnapshot.execute(() -> {
... do something that requires the previously captured context
});
If you do not want to either propagate or clear a context, you need to explicitly mark it as unchanged
. In this example we want to capture and propagate only the application context, but we don’t want to clear the transaction context because we’re going to manually set it up for the new thread where we’re going to use the captured application context:
threadContext = ThreadContext.builder()
.propagated(ThreadContext.APPLICATION)
.unchanged(ThreadContext.TRANSACTION)
.cleared(ThreadContext.ALL_REMAINING)
.build();
Callable<Integer> updateDatabase = threadContext.contextualCallable(() -> {
DataSource ds = InitialContext.doLookup("java:comp/env/ds1");
try (Connection con = ds.getConnection()) {
return con.createStatement().executeUpdate(sql);
}
}));
... on some other thread,
tx.begin();
... do transactional work
// runs as part of the transaction, but with the captured application scope
updateDatabase.call();
... more transactional work
tx.commit();