首页 >Java >java教程 >春季 - 为什么要逐名 - 拟议中的标准

春季 - 为什么要逐名 - 拟议中的标准

DDD
DDD原创
2025-01-28 22:08:11170浏览

spring-: why-spring-cannot-match-by-name-for-injection

Spring 依赖注入:为何无法自动按名称匹配?

Spring 的依赖注入机制主要基于类型,而非名称。当遇到多个相同类型的 Bean 时(例如 TenantDataSource),它不会自动回退到按参数名称匹配。这是因为 Spring 无法始终保证方法中的参数名称与 Bean 名称匹配。

Java 默认情况下不会在编译后的字节码中保留参数名称。如果没有特殊配置,参数名称(例如 tenantADataSource 和 tenantBDataSource)会在编译期间被清除,并替换为通用的名称,如 arg0 和 arg1。 因此,Spring 无法得知 tenantADataSource 指的是名为 "tenantA-dataSource" 的 Bean。

解决参数名称保留问题

可以使用 -parameters 编译器标志来保留字节码中的参数名称:

<code>javac -parameters MyClass.java</code>

即使使用了此标志,Spring 仍然不会按参数名称匹配,除非明确配置。

Spring 避免做出假设以防止意外行为。例如,如果参数名称意外交换或命名错误,或者开发人员期望不同的映射,会发生什么? 如果没有明确的指导(例如 @Qualifier),Spring 无法确定开发人员的意图,而选择抛出错误,而不是可能注入错误的 Bean。

Spring 遵循“显式优于隐式”的原则。依赖注入应该具有可预测性,并且不依赖于参数名称到 Bean 名称匹配之类的假设。Spring 的运作方式在不同的环境和框架中保持一致。某些语言或框架(如 Kotlin)默认保留参数名称,而其他语言则不保留,因此 Spring 避免依赖参数名称来实现关键功能。

何时名称匹配可以自动工作?

虽然 Spring 默认情况下不按参数名称匹配,但在某些情况下可以按参数名称匹配,但这取决于您的设置:

Spring 4.3 参数名称发现

如果使用 -parameters 标志编译代码,当存在歧义时,Spring 可以从参数名称推断 Bean 名称。

示例:

<code>@Autowired
public TenantService(TenantDataSource tenantADataSource, TenantDataSource tenantBDataSource) {
    this.tenantADataSource = tenantADataSource;
    this.tenantBDataSource = tenantBDataSource;
}</code>

如果使用了 -parameters 标志并且参数名称(tenantADataSource、tenantBDataSource)与 Bean 名称匹配,Spring 可以解决歧义。但是,这种行为在复杂的配置中并不总是可靠或可预测的,这就是为什么首选显式配置(例如 @Qualifier)。

为什么 Spring 更倾向于使用 @Qualifier?

使用 @Qualifier 可以确保清晰度并消除歧义,使开发人员和框架都能明确意图。

示例:

<code>@Autowired
public TenantService(
    @Qualifier("tenantA-dataSource") TenantDataSource tenantADataSource,
    @Qualifier("tenantB-dataSource") TenantDataSource tenantBDataSource
) {
    this.tenantADataSource = tenantADataSource;
    this.tenantBDataSource = tenantBDataSource;
}</code>

这样,Spring 就能准确知道要注入哪些 Bean,而不管参数名称或其他因素如何。

Spring 应该更智能吗?

有人可能会认为像 Spring 这样的框架应该更智能,并在存在歧义时自动将 Bean 名称与参数名称匹配。但是:

  1. 向后兼容性: 自动更改此行为可能会破坏 Bean 名称和参数名称不匹配的现有应用程序。
  2. 可预测性: 显式地解决歧义(例如,通过 @Qualifier)确保开发人员始终知道正在注入哪些 Bean。隐式假设可能会导致难以调试的问题,尤其是在大型复杂应用程序中。

真实场景中的情况

在大多数实际应用程序中:

  • 开发人员使用有意义的 Bean 名称和参数名称,但他们也更喜欢像 @Qualifier 这样的显式配置以确保清晰度。
  • 对于多实例场景,通常使用动态配置基于工厂的方法(例如 AbstractRoutingDataSource),而不是手动连接各个 Bean。

关键要点

  1. Spring 首先按类型注入: 如果只有一种类型的 Bean,Spring 会毫无问题地注入它。如果存在多种相同类型的 Bean,Spring 需要额外的提示(例如 @Qualifier)来解决歧义。
  2. 参数名称不可靠: 默认情况下,参数名称不会保留在 Java 字节码中,因此 Spring 无法使用它们将 Bean 与参数匹配。即使保留了参数名称(-parameters),Spring 也会避免隐式基于名称的匹配,除非明确配置。
  3. 显式优于隐式: Spring 优先考虑可预测性,并鼓励开发人员使用显式配置(例如 @Qualifier@Primary)而不是依赖于隐式匹配。
  4. Spring 的设计理念: 歧义错误可以防止意外行为,并确保开发人员完全控制依赖注入。

以上是春季 - 为什么要逐名 - 拟议中的标准的详细内容。更多信息请关注PHP中文网其他相关文章!

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