0

here is the following code for configuring several datasources in a spring batch project

@Configuration
@RequiredArgsConstructor
public class DatasourceConfiguration {

    private final Environment env;

    @Bean(name = "batchDataSource")
    @ConfigurationProperties(prefix = "spring.batch-datasource")
    public DataSource primaryDataSource() {
        return DataSourceBuilder.create().build();
    }

    @Bean(name = "customersDataSource")
    @ConfigurationProperties(prefix = "spring.customers-datasource")
    public DataSource secondaryDataSource() {
        return DataSourceBuilder.create().build();
    }

    @Bean
    BatchConfigurer configurer(@Qualifier("batchDataSource") DataSource dataSource) {
        return new DefaultBatchConfigurer(dataSource);
    }
}

when loading the app I get the following error:

Field dataSource in org.springframework.batch.core.configuration.annotation.AbstractBatchConfiguration required a single bean, but 2 were found:
    - batchDataSource: defined by method 'primaryDataSource' in class path resource [com/comp/lr/snapshot/customers/job/config/DatasourceConfiguration.class]
    - customersDataSource: defined by method 'secondaryDataSource' in class path resource [com/comp/lr/snapshot/customers/job/config/DatasourceConfiguration.class]

But why is it happening if I'm using @Qaulifier annotation?

nadavgam
  • 2,014
  • 5
  • 20
  • 48
  • The issue does not seem to be with the provided code, but with `org.springframework.batch.core.configuration.annotation.AbstractBatchConfiguration` instead. If you take a look at its source code (https://github.com/spring-projects/spring-batch/blob/main/spring-batch-core/src/main/java/org/springframework/batch/core/configuration/annotation/AbstractBatchConfiguration.java) you will see a `DataSource` being autowired. – João Dias Feb 06 '22 at 17:39
  • try [marking one of them as @Primary](https://stackoverflow.com/a/30538442/1211547) – indybee Feb 06 '22 at 19:23
  • using @primary does fix the issue, but why is it necessary? – nadavgam Feb 06 '22 at 20:02
  • Can you move the @Qualifier("batchDataSource") annotation over the method and try? @Bean @Qualifier("batchDataSource") BatchConfigurer configurer(DataSource dataSource) { return new DefaultBatchConfigurer(dataSource); } Primary works similarly. It simply autowires the Implementation annotated with Primary and ignores other. – bluelurker Feb 06 '22 at 21:52
  • `@Primary` fixes the issue because with it, Spring knows which bean to inject in `org.springframework.batch.core.configuration.annotation.AbstractBatchConfiguration`. – João Dias Feb 06 '22 at 23:49

1 Answers1

0

If you want this to work create your own class AbstractBatchConfiguration and mark the datasource injection with a @qualifier (for your desired datasource bean) Also exclude AbstractBatchConfiguration so that it does not get autoconfigured.

The reason is spring batch:

@Configuration(proxyBeanMethods = false)
@Import(ScopeConfiguration.class)
public abstract class AbstractBatchConfiguration implements ImportAware, InitializingBean {

    @Autowired
    private DataSource dataSource;

    private BatchConfigurer configurer;

    private JobRegistry jobRegistry = new MapJobRegistry();

    private JobBuilderFactory jobBuilderFactory;

    private StepBuilderFactory stepBuilderFactory;

class has @Autowired on the Datasource field. So Spring does not know which one of the 2 you defined to inject.

You could also annotate the batch datasource with @primary but then where ever you don't specify a datasource qualifier the batch datasource will be injected. So if another spring class has @Autowired Datasource you still have a problem.

Arno_Geismar
  • 2,296
  • 1
  • 15
  • 29