繁体   English   中英

创建名为“batchDataSource”的 bean 时出错:当前正在创建请求的 bean:是否存在无法解析的循环引用?

[英]Error creating bean with name 'batchDataSource': Requested bean is currently in creation: Is there an unresolvable circular reference?

我有一个批处理配置。 我看到批处理是默认使用InMemoryMap的。 相反,我需要使用 MySQL 来批量发送所有执行细节。 但是当我使用以下代码时,出现以下错误,

创建名为“batchDataSource”的 bean 时出错:当前正在创建请求的 bean:是否存在无法解析的循环引用?

@Configuration
@EnableBatchProcessing
public class BatchProcess extends DefaultBatchConfigurer {

    private @Autowired Environment env;

    @Bean
    @StepScope
    public ItemReader reader() {
        ...
    }

    @Bean
    @StepScope
    public ItemProcessor processor() {
        ...
    }

    @Bean
    @StepScope
    public ItemWriter writer() {
        ...
    }

    @Bean
    @Primary
    public DataSource batchDataSource() {
        HikariDataSource hikari = new HikariDataSource();
        hikari.setDriverClassName(env.getProperty("spring.datasource.driver-class-name"));
        hikari.setJdbcUrl(env.getProperty("spring.datasource.url"));
        hikari.setUsername(env.getProperty("spring.datasource.username"));
        hikari.setPassword(env.getProperty("spring.datasource.password"));
        return hikari;
    }

    public JobRepository getJobRepository() {
        JobRepositoryFactoryBean factory = new JobRepositoryFactoryBean();
        factory.setDataSource(batchDataSource());
        factory.setTransactionManager(manager());
        factory.afterPropertiesSet();
        return factory.getObject();
    }

    public PlatformTransactionManager manager() {
        return new ResourcelessTransactionManager();
    }

    @Bean
    public Step step() {
        return stepBuilderFactory.get("step")
                .chunk(1000)
                .reader(reader())
                .processor(processor())
                .writer(writer())
                .build();
    }

    @Bean
    public Job job() {
        return jobBuilderFactory.get("job")
                .flow(step())
                .end()
                .build();
    }

    @Bean
    public JobLauncher getJobLauncher() {
        SimpleJobLauncher launcher = new SimpleJobLauncher();
        launcher.setJobRepository(createJobRepository());
        return launcher;
    }
}

在我使用的属性文件中,

spring.batch.job.enabled=false
spring.batch.initialize-schema=always

那我错过了什么? 我正在使用 JPA。甚至为什么它不使用可用的 JPA 数据源? 如何强制 Spring 批次使用默认 MySQL 而不是 InMemoryMap?

首先,在 pom.xml 中显式定义 mysql-connector 依赖项,并从项目中删除与内存中 map 相关的所有内容。

  <dependency>
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-java</artifactId>
   </dependency>

如果你想用 beans 手动定义你自己的配置,那么你不能使用 AutoConfiguration 类,因为它们会在启动时自动为你创建所需的 beans,如果你定义自己的自定义数据库配置类,这可能会导致问题。 因此,您必须排除DataSourceAutoConfigurationHibernateJpaAutoConfigurationDataSourceTransactionManagerAutoConfiguration才能解决该问题。

只需更新@SpringBootApplication class:

@SpringBootApplication(
      exclude = {DataSourceAutoConfiguration.class, HibernateJpaAutoConfiguration.class,
        DataSourceTransactionManagerAutoConfiguration.class
      }
    )
    public class App {
    
      public static void main(String[] args) {
        SpringApplication.run(App.class, args);
      }
    }

您收到的错误消息可能不是最清楚的,但它应该为您指明了正确的方向。 您的代码中似乎存在循环依赖

当您有两个(或更多)相互依赖的 bean 时,会发生这种情况,从而防止在另一个不存在的情况下创建一个(反之亦然)——众所周知的鸡和蛋问题 您通常可以通过 setter 注入和某种构建后初始化来避免这种情况。

我认为您是通过扩展DefaultBatchConfigurer然后定义@Bean注释方法getJobLauncher()来创建这种情况的,该方法直接调用DefaultBatchConfigurercreateJobRepository()方法而不确保首先在DefaultBatchConfigurer中设置DataSource

这完全没有必要,因为DefaultBatchConfigurer已经按照正确的顺序为您创建了JobRepositoryJobExplorerJobLauncher

来自DefaultBatchConfigurer

@PostConstruct
    public void initialize() {
        try {
            this.jobRepository = createJobRepository();
            this.jobExplorer = createJobExplorer();
            this.jobLauncher = createJobLauncher();
        } catch (Exception e) {
            throw new BatchConfigurationException(e);
        }
    }

如果您要扩展DefaultBatchConfigurer ,那么我建议您从代码中删除以下方法

  • getJobRepository()
  • manager()
  • getJobLauncher()

从您的代码示例中,您似乎已经设置了以下属性(在您的application.properties文件中?):

spring.datasource.jdbcUrl=...
spring.datasource.username=...
spring.datasource.password=...
spring.datasource.driverClassName=...

这应该足以让 Spring 的自动配置自动为您创建一个 Hikari DataSource ,这是我通常采用的方法。 Spring Bean 名称将是dataSource ,这将通过setDataSource()自动连接到DefaultBatchConfigurer中。

但是,在您的代码示例中,您还定义了一个名为batchDataSource()@Bean注释方法,它看起来与您应该从 Spring AutoConfiguration 收到的内容没有什么不同。 只要您配置了前面提到的spring.datasource属性,您应该也可以消除batchDataSource() ,但我认为这不是必需的,所以您可以选择。

如果您仍想手动配置DataSource ,那么我建议您不要扩展DefaultBatchConfigurer而是在配置 class 中为它定义一个自定义 bean,您可以在其中直接传入自定义DataSource (基于我目前对您使用的了解案件)。

@Bean
public BatchConfigurer batchConfigurer(){
    return new DefaultBatchConfigurer( batchDataSource() );
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM