简体   繁体   中英

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. 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. However, in the service that depends on the library I want to use Basic authentication, therefore I'd create a BasicAuthUsernameProvider that overrides getUsername() .

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 . But I don't want to have the library clients specify a primary bean, but instead mark a default.

Adding @Order(value = Ordered.LOWEST_PRECEDENCE) on the DefaultUsernameProvider didn't work.

Adding @ConditionalOnMissingBean in a Configuration class in the library didn't work either.

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.

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 . 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
public class ProviderConfig {
    @Bean
    public UsernameProvider() {
         return new BasicAuthUsernameProvider();
    }
}

This bean will then be auto wired wherever its needed

You can annotate the method that instantiates your bean with @ConditionalOnMissingBean . This would mean that the method will be used to instantiate your bean only if no other UserProvider is declared as a bean.

In the example below you must not annotate the class DefaultUserProvider as Component , Service or any other bean annotation.

@Configuration
public class UserConfiguration {

  @Bean
  @ConditionalOnMissingBean
  public UserProvider provideUser() {

    return new DefaultUserProvider();
  }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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