Skip to content

CDI & Dependency Injection Basics

  • Scopes (@ApplicationScoped, @RequestScoped), @Inject, producers, and qualifiers.

1. What is CDI and how does Quarkus use it?

Section titled “1. What is CDI and how does Quarkus use it?”

Answer:
CDI (Contexts and Dependency Injection) is the standard dependency injection framework in Jakarta EE. Quarkus uses ArC, its own build-time CDI implementation that processes beans at compile time — making it fast and native-image compatible.

Key difference from Spring: CDI uses scopes tied to lifecycle contexts (HTTP request, application, session), not just singletons/prototypes.


2. What are the main CDI scopes in Quarkus?

Section titled “2. What are the main CDI scopes in Quarkus?”

Answer:

ScopeAnnotationLifecycleWhen to use
Dependent@Dependent (default)New instance per injection pointStateful, short-lived beans
Application@ApplicationScopedOne instance per app lifetimeStateless services, repositories
Request@RequestScopedOne per HTTP requestRequest-scoped state
Singleton@SingletonSame as ApplicationScoped (no proxy)Simple singletons

Most common: @ApplicationScoped for services, @RequestScoped for request-specific state.


Answer:

Field injection (simplest):

@ApplicationScoped
public class OrderService {
@Inject
UserRepository userRepo;
@Inject
EmailService emailService;
public void placeOrder(Order order) {
User user = userRepo.findById(order.userId);
emailService.sendConfirmation(user.email);
}
}

Constructor injection (recommended for testability):

@ApplicationScoped
public class OrderService {
private final UserRepository userRepo;
private final EmailService emailService;
@Inject
public OrderService(UserRepository userRepo, EmailService emailService) {
this.userRepo = userRepo;
this.emailService = emailService;
}
}

Answer:
A @Produces method creates a bean from code you control (e.g., third-party classes or conditional logic):

@ApplicationScoped
public class ConfigProducer {
@Produces
@ApplicationScoped
public ObjectMapper objectMapper() {
ObjectMapper mapper = new ObjectMapper();
mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
return mapper;
}
}
// Inject it anywhere:
@Inject
ObjectMapper mapper;

5. What are qualifiers and when do you need them?

Section titled “5. What are qualifiers and when do you need them?”

Answer:
Qualifiers distinguish between multiple beans of the same type:

// Define qualifier
@Qualifier
@Retention(RUNTIME)
@Target({FIELD, METHOD, TYPE})
public @interface Premium {}
// Two implementations
@ApplicationScoped
public class BasicEmailService implements EmailService { ... }
@ApplicationScoped
@Premium
public class PremiumEmailService implements EmailService { ... }
// Inject specific one
@Inject
@Premium
EmailService emailService;

Without a qualifier, CDI would fail with an “ambiguous dependencies” error if two beans satisfy the same type.


6. What is @Observes and how do you listen to CDI events?

Section titled “6. What is @Observes and how do you listen to CDI events?”

Answer:
CDI events allow decoupled communication between beans:

// Fire an event
@Inject
Event<UserCreatedEvent> userCreatedEvent;
public void createUser(User user) {
// ... save user
userCreatedEvent.fire(new UserCreatedEvent(user));
}
// Listen to it
public void onUserCreated(@Observes UserCreatedEvent event) {
emailService.sendWelcome(event.getUser().email);
}

Quarkus also supports startup/shutdown events:

void onStart(@Observes StartupEvent event) {
log.info("Application started");
}
void onStop(@Observes ShutdownEvent event) {
log.info("Application stopping");
}

ConceptKey Point
@ApplicationScopedOne shared instance per app
@RequestScopedNew instance per HTTP request
@InjectInjects a managed CDI bean
@ProducesCreates beans from custom factory methods
QualifierDisambiguates multiple beans of same type
@ObservesListens to CDI events (decoupled communication)
ArCQuarkus’s build-time CDI — no runtime reflection