」工欲善其事,必先利其器。「—孔子《論語.錄靈公》
首頁 > 程式設計 > 與 @Named 一起揭開挑戰

與 @Named 一起揭開挑戰

發佈於2024-09-02
瀏覽:819

在上下文和依赖注入 (CDI) 不断发展的环境中,开发人员经常遇到与 bean 命名、默认实现和潜在冲突相关的障碍。本文详细探讨了 CDI 中与 @Named 注释相关的潜在陷阱。我们将深入研究其复杂性,阐明有问题的场景,并讨论替代方法,包括使用 SmallRye 中的 @Identifier。此外,我们将提供有关构建强大且可维护的最佳实践的见解Jakarta EE
应用程序。

理解@Default

@Default 注释是 CDI 中的一个有价值的工具,用于将特定实现显式标记为给定接口或 bean 类型的默认实现。它在处理同一接口的多个实现时发挥作用,允许开发人员指定在不使用其他限定符时默认应注入哪个实现。

考虑存在 GreetingService 接口的多个实现的场景:

@Default
public class DefaultGreetingService implements GreetingService {

  @Override
  public String greet(String name) {
    return "Hello, "   name;
  }
}
public class SpecialGreetingService implements GreetingService {

  @Override
  public String greet(String name) {
    return "Greetings, "   name   "!";
  }
}

在不指定任何限定符的情况下注入 bean 时,CDI 使用 @Default 标记的 bean 作为默认值。这在具有多种实现的场景中是有益的,提供了明确的默认选择。

@Inject
private GreetingService greetingService; // Injects the @Default implementation

虽然 @Default 的使用是可选的,但强烈建议使用它,特别是在处理具有多个实现的接口时。它提供了清晰一致的默认选项,防止 Bean 注入期间出现歧义和意外行为。

探索@Named——一把双刃剑

@Named 限定符在 CDI 中发挥着基础作用,为 bean 分配人类可读的名称或标识符。开发人员在将 bean 注入其他组件时经常使用它来通过名称引用 bean。

然而,@Named 也有其自身的一系列挑战,特别是在没有额外限定符的情况下使用时。默认情况下,CDI 将非限定类名关联为 bean 名称。这可能会导致与 @Default 限定符发生冲突,从而导致 bean 注入期间出现意外行为。

@Named
public class MyBean {
  // Implementation
}

在没有显式限定符的情况下注入 MyBean 时,CDI 将仅添加 @Named 限定符,而不是 @Default 限定符。 @Default 限定符仅在 bean 或其限定符上显式指定时才应用。

@Inject
private MyBean myBean;

在这种情况下,如果存在具有相同类型名称的其他 bean,则可能会出现歧义。例如,如果有另一个名为 MyBean 的 bean,则注入将导致歧义。

为了解决这个问题,开发人员应该明确限定他们打算注入的 bean。

@Inject
@Named("myBean")
private MyBean myBean;

或者,开发人员可以为每个 bean 使用自定义限定符来消除歧义。

问题案例:歧义和意外违约

当在没有附加限定符的情况下使用@Named并且存在相同类型的多个实现时,会出现歧义。考虑以下场景:

@Named
public class ServiceA implements Service {
  // Implementation
}
@Named
public class ServiceB implements Service {
  // Implementation
}

在没有显式限定符的情况下注入服务可能会导致歧义,因为两个 bean 按类型匹配,并且没有名称或限定符区分它们。

@Inject
private Service service;

在这种情况下,CDI不会隐式添加@Default或尝试解决歧义,从而导致由于不明确的依赖关系而导致注入失败。

替代方案:从 SmallRye Common 引入 @Identifier

认识到@Named 带来的挑战,开发人员经常寻求替代方案来更明确地控制 Bean 标识。其中一种替代方案是
中的 @Identifier 注释 小黑麦常见。此注释提供了一种更清晰、更可控的 bean 命名方法,减少了冲突和意外默认的风险。与 @Named 不同,@Named 要求每个应用程序都有唯一的值,@Identifier 允许多个 bean 具有相同的标识符值,只要它们的类型不同。在处理相同接口或相关类型的不同实现时,这种灵活性特别有用。

要使用@Identifier,只需用该注解注释bean类并指定标识符值即可:

@Identifier("payment")
public class DefaultPaymentProcessor implements PaymentProcessor {
  // Implementation
}
@Identifier("payment")
public class LegacyPaymentGateway implements PaymentGateway {
  // Implementation
}

使用@Identifier注入bean很简单:

public class Client {
  @Inject
  @Identifier("payment")
  PaymentProcessor processor;

  @Inject
  @Identifier("payment")
  PaymentGateway gateway;

}

此处,“付款”@Identifier 值被多个 bean 重用,因为 PaymentProcessor 和 PaymentGateway 的类型不同。 @Named 不允许这种灵活性,其中
值在应用程序范围内必须是唯一的。

@Named 的另一种替代方法是创建自定义限定符。自定义限定符是用户定义的注释,可用于识别和限定 bean。它们提供对 Bean 选择的最精细控制,并且可以根据应用程序的特定需求进行定制。

要创建自定义限定符,请按照下列步骤操作:

  1. 定义一个新的注释类。
  2. 用@Qualifier注解注解类。
  3. (可选)为限定符提供默认值。

例如,以下名为 DefaultPaymentGateway 的自定义限定符表示默认支付网关实现:

@Qualifier
@Retention(RUNTIME)
@Target({METHOD, FIELD, PARAMETER, TYPE})
public @interface DefaultPaymentGateway {

}

要使用自定义限定符,请用它注释 bean 类:

@DefaultPaymentGateway
public class StandardPaymentGateway implements PaymentGateway {
  // Implementation
}
public class ExpressPaymentGateway implements PaymentGateway {
  // Implementation
}

然后,使用限定符注入bean:

@Inject
@DefaultPaymentGateway
private PaymentGateway paymentGateway;

选择正确的方法

bean 识别的最佳方法取决于应用程序的具体需求。对于简单的应用程序,@Named 可能就足够了。对于更复杂的应用程序,@Identifier 或
自定义限定符提供更多控制和灵活性。

下表总结了每种方法的优缺点:

方法 优点 缺点
@命名 简单,广泛支持 可能不明确,与@Default冲突
@标识符 标识更清晰,与@Default不冲突 需要额外注释
自定义限定符 最大灵活性,细粒度控制 需要前期工作来定义和维护

进一步确认,可以参考官方CDI规范

Unveiling Challenges with @Named

结论:Bean 命名和默认值的策略选择

总之,与 @Named 相关的潜在陷阱强调了在 CDI 中使用此注释时需要仔细考虑。当依赖隐式命名时,尤其是在存在多个实现的情况下,可能会出现歧义和意外的默认值。鼓励开发人员探索替代方案,例如来自 SmallRye Common 的 @Identifier,以获得更受控制和更明确的 Bean 识别方法。采用显式限定、自定义限定符和替代方法可确保更流畅、更可控的 CDI 体验,从而实现健壮且可维护的 Java。

版本聲明 本文轉載於:https://dev.to/yanev/unveiling-challenges-with-named-67p?1如有侵犯,請聯絡[email protected]刪除
最新教學 更多>
  • 如何從PHP中的數組中提取隨機元素?
    如何從PHP中的數組中提取隨機元素?
    從陣列中的隨機選擇,可以輕鬆從數組中獲取隨機項目。考慮以下數組:; 從此數組中檢索一個隨機項目,利用array_rand( array_rand()函數從數組返回一個隨機鍵。通過將$項目數組索引使用此鍵,我們可以從數組中訪問一個隨機元素。這種方法為選擇隨機項目提供了一種直接且可靠的方法。
    程式設計 發佈於2025-03-15
  • 如何使用組在MySQL中旋轉數據?
    如何使用組在MySQL中旋轉數據?
    在關係數據庫中使用mySQL組使用mySQL組進行查詢結果,在關係數據庫中使用MySQL組,轉移數據的數據是指重新排列的行和列的重排以增強數據可視化。在這裡,我們面對一個共同的挑戰:使用組的組將數據從基於行的基於列的轉換為基於列。 Let's consider the following ...
    程式設計 發佈於2025-03-15
  • 為什麼Microsoft Visual C ++無法正確實現兩台模板的實例?
    為什麼Microsoft Visual C ++無法正確實現兩台模板的實例?
    在Microsoft Visual C 中,Microsoft consions用戶strate strate strate strate strate strate strate strate strate strate strate strate strate strate strate st...
    程式設計 發佈於2025-03-15
  • 如何使用FormData()處理多個文件上傳?
    如何使用FormData()處理多個文件上傳?
    )處理多個文件輸入時,通常需要處理多個文件上傳時,通常是必要的。 The fd.append("fileToUpload[]", files[x]); method can be used for this purpose, allowing you to send multi...
    程式設計 發佈於2025-03-15
  • 在Java中使用for-to-loop和迭代器進行收集遍歷之間是否存在性能差異?
    在Java中使用for-to-loop和迭代器進行收集遍歷之間是否存在性能差異?
    For Each Loop vs. Iterator: Efficiency in Collection TraversalIntroductionWhen traversing a collection in Java, the choice arises between using a for-...
    程式設計 發佈於2025-03-15
  • 大批
    大批
    [2 數組是對象,因此它們在JS中也具有方法。 切片(開始):在新數組中提取部分數組,而無需突變原始數組。 令ARR = ['a','b','c','d','e']; // USECASE:提取直到索引作...
    程式設計 發佈於2025-03-15
  • 對象擬合:IE和Edge中的封面失敗,如何修復?
    對象擬合:IE和Edge中的封面失敗,如何修復?
    To resolve this issue, we employ a clever CSS solution that solves the problem:position: absolute;top: 50%;left: 50%;transform: translate(-50%, -50%)...
    程式設計 發佈於2025-03-15
  • 如何從Python中的字符串中刪除表情符號:固定常見錯誤的初學者指南?
    如何從Python中的字符串中刪除表情符號:固定常見錯誤的初學者指南?
    從python import codecs import codecs import codecs 導入 text = codecs.decode('這狗\ u0001f602'.encode('utf-8'),'utf-8') 印刷(文字)#帶有...
    程式設計 發佈於2025-03-15
  • 為什麼我的CSS背景圖像出現?
    為什麼我的CSS背景圖像出現?
    故障排除:CSS背景圖像未出現 ,您的背景圖像儘管遵循教程說明,但您的背景圖像仍未加載。圖像和样式表位於相同的目錄中,但背景仍然是空白的白色帆布。 而不是不棄用的,您已經使用了CSS樣式: bockent {背景:封閉圖像文件名:背景圖:url(nickcage.jpg); 如果您的html,cs...
    程式設計 發佈於2025-03-15
  • 如何干淨地刪除匿名JavaScript事件處理程序?
    如何干淨地刪除匿名JavaScript事件處理程序?
    刪除匿名事件偵聽器將匿名事件偵聽器添加到元素中會提供靈活性和簡單性,但是當要刪除它們時,可以構成挑戰,而無需替換元素本身就可以替換一個問題。 element? element.addeventlistener(event,function(){/在這里工作/},false); 要解決此問題,請考...
    程式設計 發佈於2025-03-15
  • 如何檢查對像是否具有Python中的特定屬性?
    如何檢查對像是否具有Python中的特定屬性?
    方法來確定對象屬性存在尋求一種方法來驗證對像中特定屬性的存在。考慮以下示例,其中嘗試訪問不確定屬性會引起錯誤: >>> a = someClass() >>> A.property Trackback(最近的最新電話): 文件“ ”,第1行, attributeError:SomeClass實...
    程式設計 發佈於2025-03-15
  • Python讀取CSV文件UnicodeDecodeError終極解決方法
    Python讀取CSV文件UnicodeDecodeError終極解決方法
    在試圖使用已內置的CSV模塊讀取Python中時,CSV文件中的Unicode Decode Decode Decode Decode decode Error讀取,您可能會遇到錯誤的錯誤:無法解碼字節 在位置2-3中:截斷\ uxxxxxxxx逃脫當CSV文件包含特殊字符或Unicode的路徑逃...
    程式設計 發佈於2025-03-15
  • 如何在JavaScript對像中動態設置鍵?
    如何在JavaScript對像中動態設置鍵?
    在嘗試為JavaScript對象創建動態鍵時,如何使用此Syntax jsObj['key' i] = 'example' 1;不工作。正確的方法採用方括號: jsobj ['key''i] ='example'1; 在JavaScript中,數組是一...
    程式設計 發佈於2025-03-15
  • 如何使用Regex在PHP中有效地提取括號內的文本
    如何使用Regex在PHP中有效地提取括號內的文本
    php:在括號內提取文本在處理括號內的文本時,找到最有效的解決方案是必不可少的。一種方法是利用PHP的字符串操作函數,如下所示: 作為替代 $ text ='忽略除此之外的一切(text)'; preg_match('#((。 &&& [Regex使用模式來搜索特...
    程式設計 發佈於2025-03-15
  • 為什麼使用Firefox後退按鈕時JavaScript執行停止?
    為什麼使用Firefox後退按鈕時JavaScript執行停止?
    導航歷史記錄問題:JavaScript使用Firefox Back Back 此行為是由瀏覽器緩存JavaScript資源引起的。要解決此問題並確保在後續頁面訪問中執行腳本,Firefox用戶應設置一個空功能。 警報'); }; alert('inline Alert')...
    程式設計 發佈於2025-03-15

免責聲明: 提供的所有資源部分來自互聯網,如果有侵犯您的版權或其他權益,請說明詳細緣由並提供版權或權益證明然後發到郵箱:[email protected] 我們會在第一時間內為您處理。

Copyright© 2022 湘ICP备2022001581号-3