2015-05-29 4 views
3

У меня есть простое приложение Spring Batch, которое вытаскивает записи из базы данных и просто печатает строки на экране. Просто приложение POC.Spring Batch с двумя различными проблемами с источниками данных

Приложение прекрасно работает с Spring Boot 1.2.1.RELEASE, но когда я обновился до 1.2.3.RELEASE, я получаю сообщение об ошибке «Нет определяющего компонента типа [javax.sql.DataSource] определено«

Я не уверен, что это проблема с Spring Boot или Spring Batch.

Есть ли способ явно определить источник данных для репозитория Spring Batch?

Полная трассировка стека.

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 

Пример кода

@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<AppointmentVerification> reader, 
         ItemProcessor<AppointmentVerification, AppointmentVerification> processor) { 
     return stepBuilderFactory.get("step1") 
       .<AppointmentVerification, AppointmentVerification> chunk(10)    
       .reader(reader) 
       .processor(processor) 
       .build(); 
    } 

    @Bean 
    public ItemProcessor<AppointmentVerification, AppointmentVerification> processorAppointmentVerification() { 
     return new AppointmentVerificationItemProcessor(); 
    } 

    @Bean 
    public ItemReader<AppointmentVerification> appointmentVerificationReader(DataSource consumerAppointmentDataSource) { 
     JdbcCursorItemReader<AppointmentVerification> reader = new JdbcCursorItemReader<AppointmentVerification>(); 
     String sql = "select * from test"; 
     reader.setSql(sql); 
     reader.setDataSource(consumerAppointmentDataSource); 
     reader.setRowMapper(rowMapper()); 
     return reader; 
    } 

    private RowMapper<AppointmentVerification> rowMapper() { 

     return new RowMapper<AppointmentVerification>() { 

      @Override 
      public AppointmentVerification mapRow(ResultSet rs, int i) 
        throws SQLException { 
       AppointmentVerification appointmentVerification = new AppointmentVerification(); 
       appointmentVerification.setEmail(rs.getString("CNSM_EML_ADR")); 
       return appointmentVerification; 
      } 
     }; 
    } 

} 

Отредактировано Fix: Обновлен главный источник данных для первичного Создано BatchConfigurer боб. Добавить @Qualifier в itemreader

@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<AppointmentVerification> reader, 
         ItemWriter<AppointmentVerification> messageWriter) { 
     return stepBuilderFactory.get("step1") 
       .<AppointmentVerification, AppointmentVerification> chunk(10) 
       .reader(reader) 
       .writer(messageWriter) 
       .build(); 
    } 

    @Bean 
    public ItemReader<AppointmentVerification> appointmentVerificationReader(@Qualifier(value = "consumerAppointmentDataSource") DataSource consumerAppointmentDataSource) { 
     JdbcCursorItemReader<AppointmentVerification> reader = new JdbcCursorItemReader<AppointmentVerification>(); 
     String sql = "select * from test"; 
     reader.setSql(sql); 
     reader.setDataSource(consumerAppointmentDataSource); 
     reader.setRowMapper(rowMapper()); 
     return reader; 
    } 

    private RowMapper<AppointmentVerification> rowMapper() { 

     return new RowMapper<AppointmentVerification>() { 
      @Override 
      public AppointmentVerification mapRow(ResultSet rs, int i) throws SQLException { 
       AppointmentVerification appointmentVerification = new AppointmentVerification(); 
       appointmentVerification.setEmail(rs.getString("CNSM_EML_ADR")); 
            return appointmentVerification; 
      } 
     }; 
    } 
+0

Спасибо за разъяснение этого! Образцы кода также действительно помогли мне! – Doug

ответ

7

Марк один из ваших бобов в качестве первичного

@Primary 
@Bean 
@ConfigurationProperties(prefix = "datasource.consumerappointment") 
public DataSource consumerAppointmentDataSource() { 
    return DataSourceBuilder.create().build(); 
} 

затем создать BatchConfigurer с ним

@Bean 
BatchConfigurer configurer(DataSource dataSource){ 
    return new DefaultBatchConfigurer(dataSource); 
} 
+0

Это, похоже, не сработало. Но была другая ошибка. «Чтобы использовать BatchConfigurer по умолчанию, контекст должен содержать не более чем один DataSource, найден 2" – zachariahyoung

Смежные вопросы