Spring Batch有两个不同的数据源问题

时间:2015-05-29 19:13:45

标签: java spring-boot spring-batch

我有一个简单的Spring Batch应用程序,它从数据库中提取记录并只将行打印到屏幕上。只是一个简单的POC应用程序。

应用程序可以正常使用Spring Boot 1.2.1.RELEASE,但是当我更新到1.2.3.RELEASE时,我收到一条错误消息“没有定义类型[javax.sql.DataSource]的限定bean”

我不确定这是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;
            }
        };
    }

}

编辑修复: 将主数据源更新为主数据库 创建了BatchConfigurer bean。 将@Qualifier添加到项目阅读器

@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;
            }
        };
    }

1 个答案:

答案 0 :(得分:7)

将您的一个bean标记为主要

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

然后用它创建一个BatchConfigurer

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