首页  >  文章  >  Java  >  与 @Named 一起揭开挑战

与 @Named 一起揭开挑战

WBOY
WBOY原创
2024-08-30 06:03:351092浏览

在上下文和依赖注入 (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 限定符。仅当在 bean 或其限定符上显式指定 @Default 限定符时,才会应用 @Default 限定符。

@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
}

在没有显式限定符的情况下注入 Service 可能会导致歧义,因为两个 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 不允许这种灵活性,其中
值在应用程序范围内必须是唯一的。

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:

  1. Define a new annotation class.
  2. Annotate the annotation class with @Qualifier.
  3. Optionally, provide a default value for the qualifier.

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;

Choosing the Right Approach

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

Unveiling Challenges with @Named

Conclusion: Strategic Choices for Bean Naming and Defaults

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中文网其他相关文章!

声明:
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn