I have an @AutoConfiguration class in a library that contains a @ConditionalOnMissingBean method to provide a default implementation. My app already has a regular bean method for that type, but when I deploy it, I get the following error:

***************************
APPLICATION FAILED TO START
***************************

Description:

Parameter 0 of constructor in my.package.StreamConsumerRepository required a single bean, but 2 were found:
    - defaultDynamoClient: defined by method 'defaultDynamoClient' in class path resource [my/package/library/aws/dynamodb/streams/StreamConsumerAutoConfig.class]
    - dynamoDbClient: defined by method 'dynamoDbClient' in class path resource [my/package/app/config/DatabaseConfig.class]


Action:

Consider marking one of the beans as @Primary, updating the consumer to accept multiple beans, or using @Qualifier to identify the bean that should be consumed

Here's the code that produced that error:

DatabaseConfig.java

@Configuration
public class DatabaseConfig {

  @Bean
  @Scope(ConfigurableBeanFactory.SCOPE_SINGLETON)
  public DynamoDbClient dynamoDbClient(
        @Value("${database.endpoint:#{null}}") URI endpoint, 
        @Value("${database.region:#{null}}") Region region
  ) {
    ...
  }

}

StreamConsumerAutoConfig.java

@AutoConfiguration
public class StreamConsumerAutoConfig {

  @Bean
  @ConditionalOnMissingBean(DynamoDbClient.class)
  public DynamoDbClient defaultDynamoClient(
        @Value("${streams.dynamodb.endpoint:#{null}}") URI endpoint, 
        @Value("${streams.dynamodb.region:#{null}}") Region region
  ) {
    ...
  }

}

My understanding is that @AutoConfigure classes are applied to the object-graph last and that the regular @Configuration should have been picked up first and the second shouldn't have been applied. When running tests using the main method and random port binding, it works fine, but when deployed it errors.

Yes, I know I can add @Primary to my app's bean method, but that kind of defeats the point of a conditional bean if I have to explicitly pick one everytime I use it.

Comment From: wilkinsona

Thanks for the report. Unfortunately, there isn't enough information here to diagnose the problem. For example, it could occur if StreamConsumerAutoConfig is picked up by package scanning rather than through its registration in META-INF/org.springframework.boot.autoconfigure.AutoConfiguration.imports but we can't tell if that's the case from what you've provided.

If you would like us to spend some more time investigating, please spend some time providing a complete yet minimal sample that reproduces the problem. You can share it with us by pushing it to a separate repository on GitHub or by zipping it up and attaching it to this issue.

Comment From: toadzky

it's definitely using classpath scanning - i didn't know i should add a meta-inf file for it. i haven't seen that mentioned in any of the pages i've read to try and figure out how to make this work.

Comment From: wilkinsona

Both the need to use the file and to avoid classpath scanning are described in the reference documentation:

Spring Boot checks for the presence of a META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports file within your published jar. The file should list your configuration classes, with one class name per line

Auto-configurations must be loaded only by being named in the imports file. Make sure that they are defined in a specific package space and that they are never the target of component scanning. Furthermore, auto-configuration classes should not enable component scanning to find additional components. Specific @Import annotations should be used instead.

Comment From: toadzky

ok, i'll add that and see if that fixes my issue. thanks for the quick response