title: Spring Batch with two different datasource issue
body: <p>I have a simple Spring Batch application that's pulling records from a database and just printing the rows to the screen.  Just a simple POC application.</p>
  
  <p>The application works just fine with Spring Boot 1.2.1.RELEASE but when I updated to 1.2.3.RELEASE I get an error message about "No qualifying bean of type [javax.sql.DataSource] is defined"</p>
  
  <p>I'm not sure if this is a Spring Boot issue or Spring Batch issue.</p>
  
  <p>Is there way to define the datasource explicitly for the Spring Batch repository?</p>
  
  <p>Full stack trace.</p>
  
  <pre><code>org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'org.springframework.batch.core.configuration.annotation.SimpleBatchConfiguration': Injection of autowired dependencies failed; nested exception is org.springframework.beans.factory.BeanCreationException: Could not autowire field: private java.util.Collection org.springframework.batch.core.configuration.annotation.AbstractBatchConfiguration.dataSources; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'dataSource' defined in class path resource [demo/BatchConfiguration.class]: Initialization of bean failed; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'dataSourceInitializer': Invocation of init method failed; nested exception is org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type [javax.sql.DataSource] is defined: expected single matching bean but found 2: dataSource,consumerAppointmentDataSource
      at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessPropertyValues(AutowiredAnnotationBeanPostProcessor.java:334)
      at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java:1210)
      at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:537)
      at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:476)
      at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:303)
      at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:230)
      at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:299)
      at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:194)
      at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:755)
      at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:757)
      at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:480)
      at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:686)
      at org.springframework.boot.SpringApplication.run(SpringApplication.java:320)
      at org.springframework.boot.SpringApplication.run(SpringApplication.java:957)
      at org.springframework.boot.SpringApplication.run(SpringApplication.java:946)
      at demo.Application.main(Application.java:13)
  Caused by: org.springframework.beans.factory.BeanCreationException: Could not autowire field: private java.util.Collection org.springframework.batch.core.configuration.annotation.AbstractBatchConfiguration.dataSources; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'dataSource' defined in class path resource [demo/BatchConfiguration.class]: Initialization of bean failed; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'dataSourceInitializer': Invocation of init method failed; nested exception is org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type [javax.sql.DataSource] is defined: expected single matching bean but found 2: dataSource,consumerAppointmentDataSource
      at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:561)
      at org.springframework.beans.factory.annotation.InjectionMetadata.inject(InjectionMetadata.java:88)
      at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessPropertyValues(AutowiredAnnotationBeanPostProcessor.java:331)
      ... 15 common frames omitted
  Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'dataSource' defined in class path resource [demo/BatchConfiguration.class]: Initialization of bean failed; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'dataSourceInitializer': Invocation of init method failed; nested exception is org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type [javax.sql.DataSource] is defined: expected single matching bean but found 2: dataSource,consumerAppointmentDataSource
      at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:547)
      at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:476)
      at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:303)
      at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:230)
      at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:299)
      at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:194)
      at org.springframework.beans.factory.support.DefaultListableBeanFactory.findAutowireCandidates(DefaultListableBeanFactory.java:1120)
      at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:996)
      at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:942)
      at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:533)
      ... 17 common frames omitted
  Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'dataSourceInitializer': Invocation of init method failed; nested exception is org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type [javax.sql.DataSource] is defined: expected single matching bean but found 2: dataSource,consumerAppointmentDataSource
      at org.springframework.beans.factory.annotation.InitDestroyAnnotationBeanPostProcessor.postProcessBeforeInitialization(InitDestroyAnnotationBeanPostProcessor.java:136)
      at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.applyBeanPostProcessorsBeforeInitialization(AbstractAutowireCapableBeanFactory.java:408)
      at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1566)
      at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:539)
      at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:476)
      at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:303)
      at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:230)
      at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:299)
      at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:217)
      at org.springframework.beans.factory.support.DefaultListableBeanFactory.getBean(DefaultListableBeanFactory.java:350)
      at org.springframework.beans.factory.support.DefaultListableBeanFactory.getBean(DefaultListableBeanFactory.java:331)
      at org.springframework.boot.autoconfigure.jdbc.DataSourceInitializerPostProcessor.postProcessAfterInitialization(DataSourceInitializerPostProcessor.java:62)
      at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.applyBeanPostProcessorsAfterInitialization(AbstractAutowireCapableBeanFactory.java:422)
      at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1579)
      at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:539)
      ... 26 common frames omitted
  Caused by: org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type [javax.sql.DataSource] is defined: expected single matching bean but found 2: dataSource,consumerAppointmentDataSource
      at org.springframework.beans.factory.support.DefaultListableBeanFactory.getBean(DefaultListableBeanFactory.java:365)
      at org.springframework.beans.factory.support.DefaultListableBeanFactory.getBean(DefaultListableBeanFactory.java:331)
      at org.springframework.context.support.AbstractApplicationContext.getBean(AbstractApplicationContext.java:968)
      at org.springframework.boot.autoconfigure.jdbc.DataSourceInitializer.init(DataSourceInitializer.java:67)
      at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
      at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
      at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
      at java.lang.reflect.Method.invoke(Method.java:606)
      at org.springframework.beans.factory.annotation.InitDestroyAnnotationBeanPostProcessor$LifecycleElement.invoke(InitDestroyAnnotationBeanPostProcessor.java:349)
      at org.springframework.beans.factory.annotation.InitDestroyAnnotationBeanPostProcessor$LifecycleMetadata.invokeInitMethods(InitDestroyAnnotationBeanPostProcessor.java:300)
      at org.springframework.beans.factory.annotation.InitDestroyAnnotationBeanPostProcessor.postProcessBeforeInitialization(InitDestroyAnnotationBeanPostProcessor.java:133)
      ... 40 common frames omitted
  </code></pre>
  
  <p>Sample Code</p>
  
  <pre><code>@Configuration
  @EnableBatchProcessing
  public class BatchConfiguration {
  
      @Bean   
      @ConfigurationProperties(prefix = "datasource")
      public DataSource dataSource() {
          return DataSourceBuilder.create().build();
      }
  
      @Bean
      @ConfigurationProperties(prefix = "datasource.consumerappointment")
      public DataSource consumerAppointmentDataSource() {
          return DataSourceBuilder.create().build();
      }
  
  
  
      @Bean
      public Job importUserJob(JobBuilderFactory jobs, Step s1) {
          return jobs.get("importUserJob")
                  .incrementer(new RunIdIncrementer())
                  .flow(s1)
                  .end()
                  .build();
      }
  
      @Bean
      public Step step1(StepBuilderFactory stepBuilderFactory,
                        ItemReader&lt;AppointmentVerification&gt; reader,
                        ItemProcessor&lt;AppointmentVerification, AppointmentVerification&gt; processor) {
          return stepBuilderFactory.get("step1")
                  .&lt;AppointmentVerification, AppointmentVerification&gt; chunk(10)               
                  .reader(reader)
                  .processor(processor)
                  .build();
      }
  
      @Bean
      public ItemProcessor&lt;AppointmentVerification, AppointmentVerification&gt; processorAppointmentVerification() {
          return new AppointmentVerificationItemProcessor();
      }
  
      @Bean
      public ItemReader&lt;AppointmentVerification&gt; appointmentVerificationReader(DataSource consumerAppointmentDataSource) {
          JdbcCursorItemReader&lt;AppointmentVerification&gt; reader = new JdbcCursorItemReader&lt;AppointmentVerification&gt;();
          String sql = "select * from test";
          reader.setSql(sql);
          reader.setDataSource(consumerAppointmentDataSource);
          reader.setRowMapper(rowMapper());
          return reader;
      }
  
      private RowMapper&lt;AppointmentVerification&gt; rowMapper() {
  
          return new RowMapper&lt;AppointmentVerification&gt;() {
  
              @Override
              public AppointmentVerification mapRow(ResultSet rs, int i)
                      throws SQLException {
                  AppointmentVerification appointmentVerification = new AppointmentVerification();
                  appointmentVerification.setEmail(rs.getString("CNSM_EML_ADR"));
                  return appointmentVerification;
              }
          };
      }
  
  }
  </code></pre>
  
  <p>Edited Fix:
  Updated the main datasource to primary
  Created a BatchConfigurer bean.
  Add a @Qualifier to the itemreader</p>
  
  <pre><code>@Configuration
  @EnableBatchProcessing
  public class BatchConfiguration {
  
      @Primary
      @Bean
      @ConfigurationProperties(prefix = "datasource.batch")
      public DataSource batchDataSource() {
          return DataSourceBuilder.create().build();
      }
  
      @Bean
      @ConfigurationProperties(prefix = "datasource.consumerappointment")
      public DataSource consumerAppointmentDataSource() {
          return DataSourceBuilder.create().build();
      }
  
      @Bean
      public BatchConfigurer configurer(DataSource batchDataSource){
          return new DefaultBatchConfigurer(batchDataSource);
      }
  
      @Bean
      public Job importUserJob(JobBuilderFactory jobs, Step s1) {
          return jobs.get("importUserJob")
                  .incrementer(new RunIdIncrementer())
                  .flow(s1)
                  .end()
                  .build();
      }
  
      @Bean
      public Step step1(StepBuilderFactory stepBuilderFactory,
                        ItemReader&lt;AppointmentVerification&gt; reader,
                        ItemWriter&lt;AppointmentVerification&gt; messageWriter) {
          return stepBuilderFactory.get("step1")
                  .&lt;AppointmentVerification, AppointmentVerification&gt; chunk(10)
                  .reader(reader)
                  .writer(messageWriter)
                  .build();
      }
  
      @Bean
      public ItemReader&lt;AppointmentVerification&gt; appointmentVerificationReader(@Qualifier(value = "consumerAppointmentDataSource") DataSource consumerAppointmentDataSource) {
          JdbcCursorItemReader&lt;AppointmentVerification&gt; reader = new JdbcCursorItemReader&lt;AppointmentVerification&gt;();
          String sql = "select * from test";
          reader.setSql(sql);
          reader.setDataSource(consumerAppointmentDataSource);
          reader.setRowMapper(rowMapper());
          return reader;
      }
  
      private RowMapper&lt;AppointmentVerification&gt; rowMapper() {
  
          return new RowMapper&lt;AppointmentVerification&gt;() {
              @Override
              public AppointmentVerification mapRow(ResultSet rs, int i) throws SQLException {
                  AppointmentVerification appointmentVerification = new AppointmentVerification();
                  appointmentVerification.setEmail(rs.getString("CNSM_EML_ADR"));
                                      return appointmentVerification;
              }
          };
      }
  </code></pre>