在上下文和依赖注入 (CDI) 不断发展的环境中,开发人员经常遇到与 bean 命名、默认实现和潜在冲突相关的障碍。本文详细探讨了 CDI 中与 @Named 注释相关的潜在陷阱。我们将深入研究其复杂性,阐明有问题的场景,并讨论替代方法,包括使用 SmallRye 中的 @Identifier。此外,我们将提供有关构建健壮且可维护的Jakarta EE
最佳实践的见解
应用程序。
@Default 注释是 CDI 中的一个有价值的工具,用于将特定实现显式标记为给定接口或 bean 类型的默认实现。它在处理同一接口的多个实现时发挥作用,允许开发人员指定在不使用其他限定符时默认应注入哪个实现。
考虑存在 GreetingService 接口的多个实现的场景:
在不指定任何限定符的情况下注入 bean 时,CDI 使用 @Default 标记的 bean 作为默认值。这在具有多种实现的场景中非常有用,提供了明确的默认选择。
虽然 @Default 的使用是可选的,但强烈建议使用它,特别是在处理具有多个实现的接口时。它提供了清晰一致的默认选项,防止 Bean 注入期间出现歧义和意外行为。
@Named 限定符在 CDI 中发挥着基础作用,为 bean 分配一个人类可读的名称或标识符。开发人员在将 bean 注入其他组件时经常使用它来通过名称引用 bean。
但是,@Named 也有其自身的一系列挑战,特别是在没有额外限定符的情况下使用时。默认情况下,CDI 将非限定类名关联为 bean 名称。这可能会导致与 @Default 限定符发生冲突,从而导致 Bean 注入期间出现意外行为。
在没有显式限定符的情况下注入 MyBean 时,CDI 将仅添加 @Named 限定符,而不是 @Default 限定符。仅当在 bean 或其限定符上显式指定 @Default 限定符时,才会应用 @Default 限定符。
在这种情况下,如果有其他具有相同类型名称的 bean,可能会出现歧义。例如,如果有另一个名为 MyBean 的 bean,则注入将导致歧义。
为了解决这个问题,开发人员应该明确限定他们打算注入的 Bean。
或者,开发人员可以为每个 bean 使用自定义限定符来消除歧义。
当在没有附加限定符的情况下使用 @Named 时,会出现歧义,并且存在相同类型的多个实现。考虑以下场景:
在没有显式限定符的情况下注入 Service 可能会导致歧义,因为两个 Bean 按类型匹配,并且没有名称或限定符区分它们。
在这种情况下,CDI 不会隐式添加 @Default 或尝试解决歧义,从而导致由于不明确的依赖关系而导致注入失败。
认识到 @Named 带来的挑战,开发人员经常寻求替代方案来更明确地控制 Bean 识别。其中一种替代方案是来自
的 @Identifier 注释
小黑麦常见。此注释提供了一种更清晰、更可控的 bean 命名方法,减少了冲突和意外默认的风险。与 @Named 不同,@Named 要求每个应用程序都有唯一的值,@Identifier 允许多个 bean 具有相同的标识符值,只要它们的类型不同。在处理相同接口或相关类型的不同实现时,这种灵活性特别有用。
要使用@Identifier,只需用注解注释bean类并指定标识符值:
使用@Identifier注入bean很简单:
这里,“付款”@Identifier 值被多个 bean 重用,因为 PaymentProcessor 和 PaymentGateway 的类型不同。 @Named 不允许这种灵活性,其中
值在应用程序范围内必须是唯一的。
Another alternative to @Named is to create custom qualifiers. Custom qualifiers are user-defined annotations that can be used to identify and qualify beans. They offer the most granular control over bean selection and can be tailored to specific needs of the application.
To create a custom qualifier, follow these steps:
For example, the following custom qualifier named DefaultPaymentGateway indicates the default payment gateway implementation:
@Qualifier @Retention(RUNTIME) @Target({METHOD, FIELD, PARAMETER, TYPE}) public @interface DefaultPaymentGateway { }
To use the custom qualifier, annotate the bean class with it:
@DefaultPaymentGateway public class StandardPaymentGateway implements PaymentGateway { // Implementation }
public class ExpressPaymentGateway implements PaymentGateway { // Implementation }
Then, inject the bean using the qualifier:
@Inject @DefaultPaymentGateway private PaymentGateway paymentGateway;
The best approach for bean identification depends on the specific needs of the application. For simple applications, @Named may be sufficient. For more complex applications, @Identifier or
custom qualifiers offer more control and flexibility.
The following table summarizes the pros and cons of each approach:
Approach | Pros | Cons |
---|---|---|
@Named | Simple, widely supported | Can be ambiguous, conflicts with @Default |
@Identifier | Clearer identification, no conflicts with @Default | Requires additional annotations |
Custom qualifiers | Maximum flexibility, fine-grained control | Requires upfront effort to define and maintain |
For further confirmation, you can refer to the official CDI specification
In conclusion, the potential pitfalls associated with @Named underscore the need for careful consideration when using this annotation in CDI. Ambiguity and unintended defaults can arise when relying on implicit naming, especially in the presence of multiple implementations. Developers are encouraged to explore alternatives such as @Identifier from SmallRye Common for a more controlled and explicit approach to bean identification. Embracing explicit qualification, custom qualifiers, and alternative approaches ensures a smoother and more controlled CDI experience, leading to robust and maintainable Java.
以上是与 @Named 一起揭开挑战的详细内容。更多信息请关注PHP中文网其他相关文章!