如何在 Spring 中为自动装配指定默认 bean?

How to specify a default bean for autowiring in Spring?

我正在编写库和使用该库的服务。我想要一个 UsernameProvider 服务,它负责提取登录用户的用户名。我使用图书馆本身的服务:

class AuditService {
  @Autowired
  UsernameProvider usernameProvider;

  void logChange() {
    String username = usernameProvider.getUsername();
    ...
  }
}

我想要 UsernameProvider 接口的默认实现,该接口从 JWT 的主题声明中提取用户名。但是,在依赖库的服务中,我想使用基本身份验证,因此我会创建一个覆盖 getUsername()BasicAuthUsernameProvider

当有多个相同类型的自动装配候选项(库中的DefaultUsernameProvider,服务中的BasicAuthUsernameProvider)时,我自然会出错,所以我必须标记bean在服务中为 @Primary。但是我不想让库客户端指定主 bean,而是标记为默认值。

DefaultUsernameProvider 上添加 @Order(value = Ordered.LOWEST_PRECEDENCE) 无效。

在库中的配置 class 中添加 @ConditionalOnMissingBean 也不起作用。

编辑: 事实证明,在 UsernameProvider 实现上添加 @Component classes 使 @ConditionalOnMissingBean 无用,因为 Spring Boot 尝试自动装配每个 class 注释为组件,因此抛出 "Multiple beans of type found" 异常。

您没有发布 DefaultUsernameProvider 的代码,但我猜它被注释为 @Component,因此它是自动接线的候选者,BasicAuthUsernameProvider 也是如此。如果你想控制使用其中的哪一个,而不是将它们都标记为组件,添加一个 @Configuration class,并在那里创建你的 UsernameProvider bean:

@Configuration
public class ProviderConfig {
    @Bean
    public UsernameProvider() {
         return new BasicAuthUsernameProvider();
    }
}

然后这个 bean 将在需要的地方自动连接

您可以使用 @ConditionalOnMissingBean 注释实例化 bean 的方法。这意味着只有当没有其他 UserProvider 被声明为 bean 时,该方法才会用于实例化您的 bean。

在下面的示例中,您不得将 class DefaultUserProvider 注释为 ComponentService 或任何其他 bean 注释。

@Configuration
public class UserConfiguration {

  @Bean
  @ConditionalOnMissingBean
  public UserProvider provideUser() {

    return new DefaultUserProvider();
  }
}