注入上下文和依赖注入 (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 这种灵活性是不允许的,包括 值必须是应用程序范围内唯一的值。
@named 另一种替代方法是创建自定义限定符。自定义限定符是用户定义的注释,可用于识别和限定 bean。它们提供对 bean 根据应用程序的具体需要,选择最精细的控制。
要创建自定义限制符,请按照以下步骤操作:
- 定义一个新的注释类。
- 使用@qualifier对注释类进行注释。
- (可选)为限定符提供默认值。
例如,以下名称 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 或 自定义限定符提供更多的控制和灵活性。
下表总结了各种方法的优缺点:
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
可参考官方cdi规范进一步确认
结论:bean 命名和默认值的策略选择总之,与 @named 相关潜在陷阱强调 cdi 使用此注释时需要仔细考虑。当依赖隐式命名时,特别是在多种实现的情况下,可能会出现歧义和意想不到的默认值。鼓励开发人员从smallryee等方面探索替代方案。 common@identifier,获得更多控制和更清晰的bean识别方法。采用显式限制、自定义限定符和替代方法,可以保证更流畅、更可控 cdi 体验,从而实现强健可维护的体验 java。
以上就是与 @Named 一起揭开挑战的细节,请关注图灵教育的其他相关文章!