绑定注解的价值

the value of binding annotations

使用绑定注解的典型例子是:-

public class RealBillingService implements BillingService {
    @Inject
    public RealBillingService(@PayPal CreditCardProcessor processor,
       TransactionLog transactionLog) {
         ...
}

我想了解注释的价值,因为我无法使用另一个绑定创建另一个构造函数

public class RealBillingService implements BillingService {
    @Inject
    public RealBillingService(@BankABC CreditCardProcessor processor,
       TransactionLog transactionLog) {
         ...
}

它在定义示例中看起来是多余的,所以我一定是遗漏了什么。

我可以

public class BankBillingService implements BillingService {
    @Inject
    public BankBillingService(@Bank CreditCardProcessor processor,
       TransactionLog transactionLog) {
         ...
}

但是我仍然需要绑定两个(或更多)类

bind(CreditCardProcessor.class)
    .annotatedWith(PayPal.class)
    .to(PayPalCreditCardProcessor.class);

bind(CreditCardProcessor.class)
    .annotatedWith(Bank.class)
    .to(BankCreditCardProcessor.class);

并且有一堆如果这样做的话,有点否定 Guice 的价值(根据我的理解)。

绑定注解的目标是区分相同class或类型的两个不同注入密钥。在您引用的示例中:

public class RealBillingService implements BillingService {
    @Inject
    public RealBillingService(@PayPal CreditCardProcessor processor,
       TransactionLog transactionLog) {
         ...
}

您可以提供替代实现:

public class StripeBillingService implements BillingService {
    @Inject
    public RealBillingService(@Stripe CreditCardProcessor processor,
       TransactionLog transactionLog) {
         ...
}

或者以更高的抽象度进行操作:

public class RealBillingService implements BillingService {
    @Inject
    public RealBillingService(@International CreditCardProcessor processor,
       TransactionLog transactionLog) {
         ...
}

也可以注入多个相似类型的参数:

@Inject
public RealOrderRepository(
    @Customer DataStore customerDataStore,
    @Order DataStore orderDataStore,
    @Item DataStore itemDataStore) { /* ... */ }

作为替代方案,它会在层次结构中创建多个不必要的类型,并使创建和替换通用实现变得更加困难或不可能:

// Ideally you should have implementations like InMemoryDataStore and AwsDataStore;
// the below would force InMemoryCustomerDataStore or LocalDbItemDataStore
// regardless of whether you need them or not.

public interface CustomerDataStore extends DataStore { /* empty */ }
public interface OrderDataStore extends DataStore { /* empty */ }
public interface ItemDataStore extends DataStore { /* empty */ }

@Inject
public RealOrderRepository(
    CustomerDataStore customerDataStore,
    OrderDataStore orderDataStore,
    ItemDataStore itemDataStore) { /* ... */ }

最终,您对绑定注解的使用应该非常少见,只是为了区分不同的注入请求,否则它们将是同一类型。在您的示例中,如果您不需要在同一应用程序中同时使用 @Bank CreditCardProcessor@PayPal CreditCardProcessor,则只需绑定 CreditCardProcessor 一次即可完成。但是,如果它们可能共存,那么您可以将它们绑定到相同的信用卡处理器,或不同的卡处理器,或者它可能需要更改。

另请参阅:Guice's BindingAnnotations docs and JSR-330's @Qualifier annotation docs