如何在Spring中指定用于自动装配的默认bean?

时间:2018-12-04 14:59:30

标签: java spring dependency-injection autowired

我正在编码一个库和使用该库的服务。我想要一个UsernameProvider服务,该服务负责提取已登录用户的用户名。我在库本身中使用了该服务:

class AuditService {
  @Autowired
  UsernameProvider usernameProvider;

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

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

当有多个相同类型的自动装配候选对象(库中的getUsername()和服务中的DefaultUsernameProvider)时,我自然会出错,因此我必须在服务为BasicAuthUsernameProvider。但是我不想让库客户端指定一个主bean,而是将其标记为默认值。

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

在库的Configuration类中添加DefaultUsernameProvider也不起作用。

编辑:结果是,在@ConditionalOnMissingBean实现类上添加@Component会使UsernameProvider无效,因为Spring Boot尝试自动装配每个注释为Component的类,因此抛出“找到了多个类型的豆” 异常。

2 个答案:

答案 0 :(得分:1)

您尚未发布DefaultUsernameProvider的代码,但我想它的注释为@Component,因此它是自动接线的候选对象,与BasicAuthUsernameProvider相同。如果要控制使用其中的哪个,而不是将它们都标记为组件,则添加一个@Configuration类,然后在其中创建UsernameProvider bean:

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

此bean将在需要的地方自动接线

答案 1 :(得分:1)

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

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

@Configuration
public class UserConfiguration {

  @Bean
  @ConditionalOnMissingBean
  public UserProvider provideUser() {

    return new DefaultUserProvider();
  }
}