Build time CDI dependency injection framework for Quarkus applications with conditional bean support and context management
—
Programmatic access to the CDI bean container for runtime bean resolution, context management, and lifecycle control. The BeanContainer interface provides the primary API for interacting with Arc's runtime container.
Main interface for programmatic bean container access and manipulation.
/**
* Represents a CDI bean container.
* Extensions using this API can also leverage arbitrary methods from running ArcContainer
* which can be obtained by invoking a static method Arc.container().
*/
public interface BeanContainer {
/**
* Resolves a bean instance for given bean type and qualifiers.
* Performs standard CDI resolution meaning it either returns a bean instance or throws a corresponding exception
* if the dependency is either unsatisfied or ambiguous.
*
* @param beanType type of the bean
* @param beanQualifiers bean qualifiers
* @return a bean instance; never null
*/
<T> T beanInstance(Class<T> beanType, Annotation... beanQualifiers);
/**
* Returns an instance factory for given bean type and qualifiers.
* This method performs CDI ambiguous dependency resolution and throws and exception if there are two or more beans
* with given type and qualifiers.
* If no matching bean is found, uses a default fallback factory that will attempt to instantiate a non-CDI object
* of the given class via no-args constructor.
*
* @param type bean type
* @param qualifiers bean qualifiers
* @return a bean instance factory, never null
*/
<T> Factory<T> beanInstanceFactory(Class<T> type, Annotation... qualifiers);
/**
* Returns an instance factory for given bean type and qualifiers.
* This method performs CDI ambiguous dependency resolution and throws and exception if there are two or more beans
* with given type and qualifiers.
* If no matching bean is found, delegates all calls to the supplied factory fallback.
*
* @param fallbackSupplier supplier to delegate to if there is no bean
* @param type bean type
* @param qualifiers bean qualifiers
* @return a bean instance factory, never null
*/
<T> Factory<T> beanInstanceFactory(
Supplier<Factory<T>> fallbackSupplier,
Class<T> type,
Annotation... qualifiers
);
/**
* Returns the context for RequestScoped beans.
* @return the context for jakarta.enterprise.context.RequestScoped
* @throws IllegalStateException If the container is not running
*/
ManagedContext requestContext();
interface Factory<T> {
Factory<Object> EMPTY = new Factory<Object>() {
@Override
public Instance<Object> create() {
return null;
}
};
/**
* @return a bean instance or null if no matching bean is found
*/
Instance<T> create();
}
interface Instance<T> extends AutoCloseable {
/**
* @return the underlying instance
*/
T get();
/**
* releases the underlying instance
*/
default void close();
}
}Usage Examples:
import jakarta.enterprise.context.ApplicationScoped;
import jakarta.inject.Inject;
import io.quarkus.arc.runtime.BeanContainer;
import io.quarkus.arc.Arc;
@ApplicationScoped
public class ContainerService {
@Inject
BeanContainer container;
public void demonstrateBasicUsage() {
// Direct bean instance resolution
UserService userService = container.beanInstance(UserService.class);
userService.processUser("john");
// Bean resolution with qualifiers
PaymentService premiumPayment = container.beanInstance(
PaymentService.class,
new PremiumQualifier.Literal()
);
premiumPayment.processPayment(100.0);
}
public void demonstrateFactoryUsage() {
// Create a factory for repeated bean creation
BeanContainer.Factory<NotificationService> factory =
container.beanInstanceFactory(NotificationService.class);
// Use the factory multiple times
for (int i = 0; i < 5; i++) {
try (BeanContainer.Instance<NotificationService> instance = factory.create()) {
instance.get().send("Message " + i);
} // Automatic cleanup with try-with-resources
}
}
public void demonstrateContextManagement() {
ManagedContext requestContext = container.requestContext();
if (requestContext.isActive()) {
// Request context is already active
performRequestScopedOperation();
} else {
// Manually activate request context
try {
requestContext.activate();
performRequestScopedOperation();
} finally {
requestContext.terminate();
}
}
}
private void performRequestScopedOperation() {
// Operations that require request context
RequestScopedService service = container.beanInstance(RequestScopedService.class);
service.handleRequest();
}
}Listener interface for bean container lifecycle events, allowing configuration immediately after container creation.
/**
* An interface that can be used to configure beans immediately after the BeanContainer has been
* created. The container is passed to the interface and beans can be obtained and be modified.
* This provides a convenient way to pass configuration from the deployment processors into runtime beans.
*/
public interface BeanContainerListener {
void created(BeanContainer container);
}Usage Examples:
import io.quarkus.arc.runtime.BeanContainer;
import io.quarkus.arc.runtime.BeanContainerListener;
public class DatabaseConfigurationListener implements BeanContainerListener {
private final String databaseUrl;
private final String username;
private final String password;
public DatabaseConfigurationListener(String databaseUrl, String username, String password) {
this.databaseUrl = databaseUrl;
this.username = username;
this.password = password;
}
@Override
public void created(BeanContainer container) {
// Configure database service after container creation
DatabaseService dbService = container.beanInstance(DatabaseService.class);
dbService.configure(databaseUrl, username, password);
// Initialize connection pool
ConnectionPoolManager poolManager = container.beanInstance(ConnectionPoolManager.class);
poolManager.initializePool();
// Setup cache if available
BeanContainer.Factory<CacheService> cacheFactory =
container.beanInstanceFactory(CacheService.class);
try (BeanContainer.Instance<CacheService> cacheInstance = cacheFactory.create()) {
if (cacheInstance != null) {
cacheInstance.get().initialize();
}
}
}
}
// Usage in configuration
public class AppInitializer {
public void setupApplication() {
// Register listener to be called when container is created
BeanContainerListener listener = new DatabaseConfigurationListener(
"jdbc:postgresql://localhost:5432/mydb",
"user",
"password"
);
// The listener will be called automatically by the framework
// (actual registration mechanism depends on the framework integration)
}
}Complex container manipulation patterns for sophisticated use cases.
import jakarta.enterprise.context.ApplicationScoped;
import jakarta.enterprise.util.AnnotationLiteral;
import jakarta.inject.Qualifier;
import io.quarkus.arc.runtime.BeanContainer;
import io.quarkus.arc.Arc;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.function.Supplier;
@ApplicationScoped
public class AdvancedContainerService {
public void demonstrateFactoryWithFallback() {
BeanContainer container = Arc.container();
// Create factory with custom fallback
Supplier<BeanContainer.Factory<ExternalService>> fallbackSupplier = () ->
() -> () -> new MockExternalService(); // Triple lambda for Factory<Instance<T>>
BeanContainer.Factory<ExternalService> factory = container.beanInstanceFactory(
fallbackSupplier,
ExternalService.class
);
try (BeanContainer.Instance<ExternalService> instance = factory.create()) {
ExternalService service = instance.get();
service.performOperation();
}
}
public void demonstrateQualifiedBeanResolution() {
BeanContainer container = Arc.container();
// Resolution with multiple qualifiers
PaymentProcessor processor = container.beanInstance(
PaymentProcessor.class,
new PaymentProvider.Literal("stripe"),
new Environment.Literal("production")
);
processor.processPayment(250.0);
}
public <T> void demonstrateGenericBeanManagement(Class<T> beanType) {
BeanContainer container = Arc.container();
// Generic bean factory creation
BeanContainer.Factory<T> factory = container.beanInstanceFactory(beanType);
// Create and manage multiple instances
for (int i = 0; i < 3; i++) {
try (BeanContainer.Instance<T> instance = factory.create()) {
T bean = instance.get();
if (bean instanceof Processable) {
((Processable) bean).process("Item " + i);
}
}
}
}
public void demonstrateContextLifecycleManagement() {
BeanContainer container = Arc.container();
ManagedContext requestContext = container.requestContext();
// Complex context management
boolean wasActive = requestContext.isActive();
if (!wasActive) {
requestContext.activate();
}
try {
// Perform operations requiring request context
RequestScopedDataHolder dataHolder =
container.beanInstance(RequestScopedDataHolder.class);
dataHolder.storeData("key", "value");
// Process with request-scoped beans
RequestProcessor processor =
container.beanInstance(RequestProcessor.class);
processor.processRequest();
} finally {
if (!wasActive) {
requestContext.terminate();
}
}
}
}
// Supporting interfaces and classes
interface ExternalService {
void performOperation();
}
class MockExternalService implements ExternalService {
public void performOperation() {
System.out.println("Mock external service operation");
}
}
interface PaymentProcessor {
void processPayment(double amount);
}
interface Processable {
void process(String item);
}
@Qualifier
@Retention(RetentionPolicy.RUNTIME)
@interface PaymentProvider {
String value();
class Literal extends AnnotationLiteral<PaymentProvider> implements PaymentProvider {
private final String value;
public Literal(String value) { this.value = value; }
public String value() { return value; }
}
}
@Qualifier
@Retention(RetentionPolicy.RUNTIME)
@interface Environment {
String value();
class Literal extends AnnotationLiteral<Environment> implements Environment {
private final String value;
public Literal(String value) { this.value = value; }
public String value() { return value; }
}
}
@ApplicationScoped
class RequestScopedDataHolder {
public void storeData(String key, String value) {
// Store data in request scope
}
}
@ApplicationScoped
class RequestProcessor {
public void processRequest() {
// Process request
}
}Common patterns for integrating container management with application architecture.
import jakarta.enterprise.context.ApplicationScoped;
import jakarta.enterprise.event.Observes;
import io.quarkus.runtime.StartupEvent;
import io.quarkus.arc.runtime.BeanContainer;
import io.quarkus.arc.Arc;
@ApplicationScoped
public class ApplicationLifecycleManager {
public void onStartup(@Observes StartupEvent event) {
BeanContainer container = Arc.container();
// Initialize critical services
initializeCriticalServices(container);
// Setup scheduled tasks
setupScheduledTasks(container);
// Warm up caches
warmupCaches(container);
}
private void initializeCriticalServices(BeanContainer container) {
// Initialize database connections
DatabaseConnectionManager dbManager =
container.beanInstance(DatabaseConnectionManager.class);
dbManager.initialize();
// Setup security services
SecurityManager securityManager =
container.beanInstance(SecurityManager.class);
securityManager.initialize();
}
private void setupScheduledTasks(BeanContainer container) {
// Create factory for task services
BeanContainer.Factory<TaskScheduler> schedulerFactory =
container.beanInstanceFactory(TaskScheduler.class);
try (BeanContainer.Instance<TaskScheduler> schedulerInstance = schedulerFactory.create()) {
TaskScheduler scheduler = schedulerInstance.get();
scheduler.scheduleRecurringTasks();
}
}
private void warmupCaches(BeanContainer container) {
// Warmup various cache services
String[] cacheTypes = {"user", "product", "configuration"};
for (String cacheType : cacheTypes) {
try {
CacheService cache = container.beanInstance(
CacheService.class,
new CacheType.Literal(cacheType)
);
cache.warmup();
} catch (Exception e) {
// Log warning but continue with other caches
System.err.println("Failed to warmup cache: " + cacheType);
}
}
}
}
// Service discovery pattern
@ApplicationScoped
public class ServiceDiscovery {
public <T> List<T> findAllServices(Class<T> serviceType) {
BeanContainer container = Arc.container();
// This is a simplified example - real implementation would need
// to use Arc's internal APIs for bean discovery
List<T> services = new ArrayList<>();
try {
T service = container.beanInstance(serviceType);
services.add(service);
} catch (Exception e) {
// No bean found or ambiguous resolution
}
return services;
}
public <T> Optional<T> findService(Class<T> serviceType, Annotation... qualifiers) {
BeanContainer container = Arc.container();
try {
T service = container.beanInstance(serviceType, qualifiers);
return Optional.of(service);
} catch (Exception e) {
return Optional.empty();
}
}
}
// Supporting classes
interface DatabaseConnectionManager {
void initialize();
}
interface SecurityManager {
void initialize();
}
interface TaskScheduler {
void scheduleRecurringTasks();
}
interface CacheService {
void warmup();
}
@Qualifier
@Retention(RetentionPolicy.RUNTIME)
@interface CacheType {
String value();
class Literal extends AnnotationLiteral<CacheType> implements CacheType {
private final String value;
public Literal(String value) { this.value = value; }
public String value() { return value; }
}
}import io.quarkus.arc.Arc;
import io.quarkus.arc.ArcContainer;
public class DirectContainerAccess {
public void useArcContainer() {
// Access Arc container directly
ArcContainer arcContainer = Arc.container();
// Arc container provides additional methods beyond BeanContainer
UserService userService = arcContainer.instance(UserService.class).get();
userService.processUser("jane");
// Check if container is running
if (arcContainer.isRunning()) {
// Container operations
}
}
}import jakarta.enterprise.context.ApplicationScoped;
import jakarta.inject.Inject;
import io.quarkus.arc.runtime.BeanContainer;
@ApplicationScoped
public class InjectionBasedAccess {
@Inject
BeanContainer container;
public void useBeanContainer() {
// Use injected container
SomeService service = container.beanInstance(SomeService.class);
service.performAction();
}
}import jakarta.enterprise.inject.UnsatisfiedResolutionException;
import jakarta.enterprise.inject.AmbiguousResolutionException;
@ApplicationScoped
public class SafeContainerUsage {
@Inject
BeanContainer container;
public void safelyResolveBean() {
try {
PaymentService paymentService = container.beanInstance(PaymentService.class);
paymentService.processPayment(100.0);
} catch (UnsatisfiedResolutionException e) {
// No bean found
System.err.println("No PaymentService implementation found");
} catch (AmbiguousResolutionException e) {
// Multiple beans found without qualifiers
System.err.println("Multiple PaymentService implementations found, use qualifiers");
}
}
public void safelyUseFactory() {
BeanContainer.Factory<OptionalService> factory =
container.beanInstanceFactory(OptionalService.class);
try (BeanContainer.Instance<OptionalService> instance = factory.create()) {
if (instance != null) {
OptionalService service = instance.get();
service.performOptionalOperation();
} else {
// Handle case where no bean was found
System.out.println("Optional service not available");
}
}
}
}@ApplicationScoped
public class ResourceManagement {
@Inject
BeanContainer container;
public void properResourceHandling() {
// Always use try-with-resources for Instance objects
BeanContainer.Factory<ResourceIntensiveService> factory =
container.beanInstanceFactory(ResourceIntensiveService.class);
try (BeanContainer.Instance<ResourceIntensiveService> instance = factory.create()) {
ResourceIntensiveService service = instance.get();
service.performHeavyOperation();
} // Automatic resource cleanup
}
}Install with Tessl CLI
npx tessl i tessl/maven-io-quarkus--quarkus-arc