EJB Container Dependency Injection
If we have more than one bean that implements a particular
bean type, the injection point can specify exactly which bean
should be injected using a qualifier annotation.
@Qualifier
@Retention(RUNTIME)
@Target({TYPE, METHOD, FIELD, PARAMETER})
public @interface Synchronous {}
@Synchronous
public class SynchronousPaymentProcessor implements
PaymentProcessor {
public void process(Payment payment)
{ ... }
@Qualifier
@Retention(RUNTIME)
@Target({TYPE, METHOD, FIELD, PARAMETER})
public @interface Asynchronous {}
@Asynchronous
public class AsynchronousPaymentProcessor implements
PaymentProcessor {
public void process(Payment payment)
{ ... }
The dependency injection of those fields could be done on
following ways;
1. Field
@Inject @Synchronous PaymentProcessor
syncPaymentProcessor;
@Inject @Asynchronous PaymentProcessor
asyncPaymentProcessor;
2. Using initializer method injection:
@Inject public void setPaymentProcessors (@Synchronous
PaymentProcessor syncPaymentProcessor, @Asynchronous
PaymentProcessor asyncPaymentProcessor){
[Link] = syncPaymentProcessor;
[Link] = asyncPaymentProcessor;
3. Using constructor injection:
@Inject
public Checkout
(@Synchronous PaymentProcessor syncPaymentProcessor,
@Asynchronous PaymentProcessor
asyncPaymentProcessor)
this
.syncPaymentProcessor = syncPaymentProcessor;
this
.asyncPaymentProcessor = asyncPaymentProcessor;
}
Combining qualified arguments with producer methods is a
good way to have an implementation of a bean type selected at
runtime based on the state of the system:
@Produces
PaymentProcessor getPaymentProcessor
(@Synchronous PaymentProcessor syncPaymentProcessor,
@Asynchronous PaymentProcessor
asyncPaymentProcessor)
return
isSynchronous() ? syncPaymentProcessor :
asyncPaymentProcessor;
If an injected field or a parameter of a bean constructor or
initializer method is not explicitly annotated with a qualifier, the
default qualifier,@Default, is assumed
a qualifier is like an extension of the interface. It does not create
a direct dependency to any particular implementation. There
may be multiple alternative implementations of
@Asynchronous PaymentProcessor!
@Any
by explicitly specifying @Any at an injection point, you
suppress the default qualifier, without otherwise restricting the
beans that are eligible for injection.
This is especially useful if you want to iterate over all beans
with a certain bean type
import
[Link];
...
@Inject
void initServices(@Any Instance<Service> services)
{
for
(Service service: services) {
[Link]();
Qualifier with members
instead of creating several qualifiers representing different
payment methods, we could aggregate them into a single
annotation with a member:
@Qualifier
@Retention
(RUNTIME)
@Target
({METHOD, FIELD, PARAMETER, TYPE})
public @interface
PayBy {
PaymentMethod value()
Then we select one of the possible member values when
applying the qualifier:
private @Inject @PayBy(CHECK) PaymentProcessor checkPayment;
We can force the container to ignore a member of a qualifier
type by annotating the member @Nonbinding.
@Qualifier
@Retention(RUNTIME)
@Target({METHOD, FIELD, PARAMETER, TYPE})
public @interface PayBy {
PaymentMethod value();
@Nonbinding String comment() default "";
Multiple qualifiers
An injection point may specify multiple qualifiers:
@Inject @Synchronous @Reliable PaymentProcessor syncPaymentProcessor;
Then only a bean which has both qualifier annotations would be
eligible for injection.
@Synchronous @Reliable
public class SynchronousReliablePaymentProcessor implements PaymentProcessor {
public void process(Payment payment) { ... }
Alternatives
Alternatives are beans whose implementation is specific to a
particular client module or deployment scenario. This alternative
defines a mock implementation of both @Synchronous
PaymentProcessor and @Asynchronous
PaymentProcessor, all in one:
@Alternative @Synchronous @Asynchronous
public class MockPaymentProcessor implements PaymentProcessor {
public void process(Payment payment) { ... }
From CDI 1.1 onwards the alternative can be enabled for the
whole application using @Priority annotation.
@Priority(100) @Alternative @Synchronous @Asynchronous
public class MockPaymentProcessor implements PaymentProcessor {
public void process(Payment payment) { ... }
When an ambiguous dependency exists at an injection point, the
container attempts to resolve the ambiguity by looking for an
enabled alternative among the beans that could be injected. If
there is exactly one enabled alternative, that’s the bean that will
be injected. If there are more beans with priority, the one with
the highest priority value is selected.