In order to use ManagedExecutor
and ThreadContext
as CDI beans, define producer for them as @ApplicationScoped
so that instances are shared and reused. In most cases, more granular and shorter-lived scopes are undesirable. For instance, having a new ManagedExecutor
instance created per HTTP request typically does not make sense. In the event that a more granular scope is desired, the application must take care to supply a disposer to ensure that the executor is shut down once it is no longer needed. When using application scope, it is optional to supply a disposer because the specification requires the container to automatically shut down ManagedExecutor
instances when the application stops.
Example qualifier,
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import javax.inject.Qualifier;
@Qualifier
@Retention(RetentionPolicy.RUNTIME)
@Target({ ElementType.FIELD, ElementType.METHOD, ElementType.PARAMETER })
public @interface SecurityAndCDIContext {}
Example producer and disposer,
import org.eclipse.microprofile.concurrent.ManagedExecutor;
import org.eclipse.microprofile.concurrent.ThreadContext;
import javax.enterprise.context.ApplicationScoped;
import javax.enterprise.inject.Produces;
@ApplicationScoped
public class MyFirstBean {
@Produces @ApplicationScoped @SecurityAndCDIContext
ManagedExecutor executor = ManagedExecutor.builder()
.propagated(ThreadContext.SECURITY, ThreadContext.CDI)
.build();
void disposeExecutor(@Disposes @SecurityAndCDIContext ManagedExecutor exec) {
exec.shutdownNow();
}
}
Example injection point,
import org.eclipse.microprofile.concurrent.ManagedExecutor;
import javax.enterprise.context.ApplicationScoped;
import javax.inject.Inject;
@ApplicationScoped
public class MySecondBean {
@Inject @SecurityAndCDIContext
ManagedExecutor sameExecutor;
...
}
Example qualifier,
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import javax.inject.Qualifier;
@Qualifier
@Retention(RetentionPolicy.RUNTIME)
@Target({ ElementType.FIELD, ElementType.METHOD, ElementType.PARAMETER })
public @interface AppContext {}
Example producer method,
import org.eclipse.microprofile.concurrent.ThreadContext;
import javax.enterprise.context.ApplicationScoped;
import javax.enterprise.inject.Produces;
@ApplicationScoped
public class MyFirstBean {
@Produces @ApplicationScoped @AppContext
createAppContextPropagator() {
return ThreadContext.builder()
.propagated(ThreadContext.APPLICATION)
.cleared(ThreadContext.SECURITY, ThreadContext.TRANSACTION)
.unchanged(ThreadContext.ALL_REMAINING)
.build();
}
}
Example injection point,
import org.eclipse.microprofile.concurrent.ThreadContext;
import javax.enterprise.context.ApplicationScoped;
import javax.inject.Inject;
...
@ApplicationScoped
public class MySecondBean {
Function<Integer, Item> findItem;
@Inject
protected void setFindItem(@AppContext ThreadContext appContext) {
findItem = appContext.contextualFunction(i -> {
try (Connection con =
((DataSource) InitialContext.doLookup("java:comp/env/ds1")).getConnection();
PreparedStatement stmt = con.prepareStatement(sql)) {
stmt.setInt(1, i);
return toItem(stmt.executeQuery());
} catch (Exception x) {
throw new CompletionException(x);
}
});
}
...
}