简体   繁体   English

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

[英]How to specify a default bean for autowiring in Spring?

I am coding both a library and service consuming this library. 我正在编写使用此库的库和服务。 I want to have a UsernameProvider service, which takes care of extracting the username of the logged in user. 我想要一个UsernameProvider服务,它负责提取登录用户的用户名。 I consume the service in the library itself: 我在库中使用服务:

class AuditService {
  @Autowired
  UsernameProvider usernameProvider;

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

I want to have a default implementation of the UsernameProvider interface that extracts the username from the subject claim of a JWT. 我希望有一个UsernameProvider接口的默认实现,它从JWT的主题声明中提取用户名。 However, in the service that depends on the library I want to use Basic authentication, therefore I'd create a BasicAuthUsernameProvider that overrides getUsername() . 但是,在依赖于库的服务中,我想使用基本身份验证,因此我创建了一个覆盖getUsername()BasicAuthUsernameProvider

I naturally get an error when there are multiple autowire candidates of the same type ( DefaultUsernameProvider in the library, and BasicAuthUsernameProvider in the service), so I'd have to mark the bean in the service as @Primary . 当有多个相同类型的autowire候选者( DefaultUsernameProvider中的DefaultUsernameProvider和服务中的BasicAuthUsernameProvider )时,我自然会收到错误,因此我必须将服务中的bean标记为@Primary But I don't want to have the library clients specify a primary bean, but instead mark a default. 但我不希望库客户端指定主bean,而是标记默认值。

Adding @Order(value = Ordered.LOWEST_PRECEDENCE) on the DefaultUsernameProvider didn't work. 添加@Order(value = Ordered.LOWEST_PRECEDENCE)DefaultUsernameProvider没有工作。

Adding @ConditionalOnMissingBean in a Configuration class in the library didn't work either. @ConditionalOnMissingBean中的Configuration类中添加@ConditionalOnMissingBean也不起作用。

EDIT: Turns out, adding @Component on the UsernameProvider implementation classes renders @ConditionalOnMissingBean useless, as Spring Boot tries to autowire every class annotated as a Component, therefore throwing the "Multiple beans of type found" exception. 编辑:结果,在UsernameProvider实现类上添加@Component使得@ConditionalOnMissingBean无用,因为Spring Boot试图将每个注释为Component的类自动装配,因此抛出“找到类型的多个bean”异常。

You've not posted the code for DefaultUsernameProvider but I guess its annotated as a @Component so it is a candidate for auto wiring, and the same with the BasicAuthUsernameProvider . 你没有发布DefaultUsernameProvider的代码,但我猜它注释为@Component因此它是自动连线的候选者,与BasicAuthUsernameProvider相同。 If you want to control which of these is used, rather than marking them both as components, add a @Configuration class, and create your UsernameProvider bean there: 如果要控制使用其中的哪一个,而不是将它们都标记为组件,请添加@Configuration类,并在那里创建UsernameProvider bean:

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

This bean will then be auto wired wherever its needed 然后,这个bean将在需要的任何地方自动连接

You can annotate the method that instantiates your bean with @ConditionalOnMissingBean . 您可以使用@ConditionalOnMissingBean注释实例化bean的方法。 This would mean that the method will be used to instantiate your bean only if no other UserProvider is declared as a bean. 这意味着只有在没有其他UserProvider被声明为bean时,该方法才会用于实例化bean。

In the example below you must not annotate the class DefaultUserProvider as Component , Service or any other bean annotation. 在下面的示例中,您不能将类DefaultUserProvider注释为ComponentService或任何其他bean注释。

@Configuration
public class UserConfiguration {

  @Bean
  @ConditionalOnMissingBean
  public UserProvider provideUser() {

    return new DefaultUserProvider();
  }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM