”工欲善其事,必先利其器。“—孔子《论语.录灵公》
首页 > 编程 > 与 @Named 一起揭开挑战

与 @Named 一起揭开挑战

发布于2024-09-02
浏览:639

在上下文和依赖注入 (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]删除
最新教程 更多>
  • 切换到MySQLi后CodeIgniter连接MySQL数据库失败原因
    切换到MySQLi后CodeIgniter连接MySQL数据库失败原因
    Unable to Connect to MySQL Database: Troubleshooting Error MessageWhen attempting to switch from the MySQL driver to the MySQLi driver in CodeIgniter,...
    编程 发布于2025-07-03
  • 在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-07-03
  • 如何从PHP中的数组中提取随机元素?
    如何从PHP中的数组中提取随机元素?
    从阵列中的随机选择,可以轻松从数组中获取随机项目。考虑以下数组:; 从此数组中检索一个随机项目,利用array_rand( array_rand()函数从数组返回一个随机键。通过将$项目数组索引使用此键,我们可以从数组中访问一个随机元素。这种方法为选择随机项目提供了一种直接且可靠的方法。
    编程 发布于2025-07-03
  • 如何将来自三个MySQL表的数据组合到新表中?
    如何将来自三个MySQL表的数据组合到新表中?
    mysql:从三个表和列的新表创建新表 答案:为了实现这一目标,您可以利用一个3-way Join。 选择p。*,d.content作为年龄 来自人为p的人 加入d.person_id = p.id上的d的详细信息 加入T.Id = d.detail_id的分类法 其中t.taxonomy =...
    编程 发布于2025-07-03
  • CSS强类型语言解析
    CSS强类型语言解析
    您可以通过其强度或弱输入的方式对编程语言进行分类的方式之一。在这里,“键入”意味着是否在编译时已知变量。一个例子是一个场景,将整数(1)添加到包含整数(“ 1”)的字符串: result = 1 "1";包含整数的字符串可能是由带有许多运动部件的复杂逻辑套件无意间生成的。它也可以是故意从单个真理...
    编程 发布于2025-07-03
  • Java中如何使用观察者模式实现自定义事件?
    Java中如何使用观察者模式实现自定义事件?
    在Java 中创建自定义事件的自定义事件在许多编程场景中都是无关紧要的,使组件能够基于特定的触发器相互通信。本文旨在解决以下内容:问题语句我们如何在Java中实现自定义事件以促进基于特定事件的对象之间的交互,定义了管理订阅者的类界面。以下代码片段演示了如何使用观察者模式创建自定义事件: args)...
    编程 发布于2025-07-03
  • input: Why Does "Warning: mysqli_query() expects parameter 1 to be mysqli, resource given" Error Occur and How to Fix It?

output: 解决“Warning: mysqli_query() 参数应为 mysqli 而非 resource”错误的解析与修复方法
    input: Why Does "Warning: mysqli_query() expects parameter 1 to be mysqli, resource given" Error Occur and How to Fix It? output: 解决“Warning: mysqli_query() 参数应为 mysqli 而非 resource”错误的解析与修复方法
    mysqli_query()期望参数1是mysqli,resource给定的,尝试使用mysql Query进行执行MySQLI_QUERY_QUERY formation,be be yessqli:sqli:sqli:sqli:sqli:sqli:sqli: mysqli,给定的资源“可能发...
    编程 发布于2025-07-03
  • JavaScript计算两个日期之间天数的方法
    JavaScript计算两个日期之间天数的方法
    How to Calculate the Difference Between Dates in JavascriptAs you attempt to determine the difference between two dates in Javascript, consider this s...
    编程 发布于2025-07-03
  • Python中何时用"try"而非"if"检测变量值?
    Python中何时用"try"而非"if"检测变量值?
    使用“ try“ vs.” if”来测试python 在python中的变量值,在某些情况下,您可能需要在处理之前检查变量是否具有值。在使用“如果”或“ try”构建体之间决定。“ if” constructs result = function() 如果结果: 对于结果: ...
    编程 发布于2025-07-03
  • 反射动态实现Go接口用于RPC方法探索
    反射动态实现Go接口用于RPC方法探索
    在GO 使用反射来实现定义RPC式方法的界面。例如,考虑一个接口,例如:键入myService接口{ 登录(用户名,密码字符串)(sessionId int,错误错误) helloworld(sessionid int)(hi String,错误错误) } 替代方案而不是依靠反射...
    编程 发布于2025-07-03
  • 如何使用PHP从XML文件中有效地检索属性值?
    如何使用PHP从XML文件中有效地检索属性值?
    从php $xml = simplexml_load_file($file); foreach ($xml->Var[0]->attributes() as $attributeName => $attributeValue) { echo $attributeName,...
    编程 发布于2025-07-03
  • 如何限制动态大小的父元素中元素的滚动范围?
    如何限制动态大小的父元素中元素的滚动范围?
    在交互式接口中实现垂直滚动元素的CSS高度限制问题:考虑一个布局,其中我们具有与用户垂直滚动一起移动的可滚动地图div,同时与固定的固定sidebar保持一致。但是,地图的滚动无限期扩展,超过了视口的高度,阻止用户访问页面页脚。$("#map").css({ marginT...
    编程 发布于2025-07-03
  • CSS可以根据任何属性值来定位HTML元素吗?
    CSS可以根据任何属性值来定位HTML元素吗?
    靶向html元素,在CSS 中使用任何属性值,在CSS中,可以基于特定属性(如下所示)基于特定属性的基于特定属性的emants目标元素: 字体家庭:康斯拉斯(Consolas); } 但是,出现一个常见的问题:元素可以根据任何属性值而定位吗?本文探讨了此主题。的目标元素有任何任何属性值,属...
    编程 发布于2025-07-03
  • 查找当前执行JavaScript的脚本元素方法
    查找当前执行JavaScript的脚本元素方法
    如何引用当前执行脚本的脚本元素在某些方案中理解问题在某些方案中,开发人员可能需要将其他脚本动态加载其他脚本。但是,如果Head Element尚未完全渲染,则使用document.getElementsbytagname('head')[0] .appendChild(v)的常规方...
    编程 发布于2025-07-03
  • 为什么我会收到MySQL错误#1089:错误的前缀密钥?
    为什么我会收到MySQL错误#1089:错误的前缀密钥?
    mySQL错误#1089:错误的前缀键错误descript [#1089-不正确的前缀键在尝试在表中创建一个prefix键时会出现。前缀键旨在索引字符串列的特定前缀长度长度,可以更快地搜索这些前缀。了解prefix keys `这将在整个Movie_ID列上创建标准主键。主密钥对于唯一识别...
    编程 发布于2025-07-03

免责声明: 提供的所有资源部分来自互联网,如果有侵犯您的版权或其他权益,请说明详细缘由并提供版权或权益证明然后发到邮箱:[email protected] 我们会第一时间内为您处理。

Copyright© 2022 湘ICP备2022001581号-3