创建名称为 'batchDataSource' 的 bean 时出错:当前正在创建请求的 bean:是否存在无法解析的循环引用?
Error creating bean with name 'batchDataSource': Requested bean is currently in creation: Is there an unresolvable circular reference?
我有一个批量配置。我看到批处理是默认使用 InMemoryMap
。相反,我需要使用 MySQL 来批量发送所有执行细节。但是当我使用以下代码时,出现以下错误,
Error creating bean with name 'batchDataSource': Requested bean is
currently in creation: Is there an unresolvable circular reference?
@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 依赖项,并从项目中删除与内存映射相关的任何内容。
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
如果你想用 beans 手动定义你自己的配置,那么你不能使用 AutoConfiguration classes 因为它们会在启动时自动为你创建所需的 beans,如果你这样做可能会导致问题正在定义自己的自定义数据库配置 classes。因此,您必须排除 DataSourceAutoConfiguration
、HibernateJpaAutoConfiguration
和 DataSourceTransactionManagerAutoConfiguration
才能解决问题。
只需更新 @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 时,会发生这种情况,从而防止在另一个不存在的情况下创建一个 bean(反之亦然)- 谚语中的先有鸡还是先有蛋问题。您通常可以通过 setter 注入和某种 post 构造初始化来避免这种情况。
我认为您是通过扩展 DefaultBatchConfigurer
然后定义直接调用 DefaultBatchConfigurer
的 createJobRepository()
的 @Bean
注释方法 getJobLauncher()
造成这种情况的不确保 DataSource
首先在 DefaultBatchConfigurer
.
内设置的方法
这完全没有必要,因为 DefaultBatchConfigurer
已经以正确的顺序为您创建了 JobRepository
、JobExplorer
和 JobLauncher
.
@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() );
}
我有一个批量配置。我看到批处理是默认使用 InMemoryMap
。相反,我需要使用 MySQL 来批量发送所有执行细节。但是当我使用以下代码时,出现以下错误,
Error creating bean with name 'batchDataSource': Requested bean is currently in creation: Is there an unresolvable circular reference?
@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 依赖项,并从项目中删除与内存映射相关的任何内容。
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
如果你想用 beans 手动定义你自己的配置,那么你不能使用 AutoConfiguration classes 因为它们会在启动时自动为你创建所需的 beans,如果你这样做可能会导致问题正在定义自己的自定义数据库配置 classes。因此,您必须排除 DataSourceAutoConfiguration
、HibernateJpaAutoConfiguration
和 DataSourceTransactionManagerAutoConfiguration
才能解决问题。
只需更新 @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 时,会发生这种情况,从而防止在另一个不存在的情况下创建一个 bean(反之亦然)- 谚语中的先有鸡还是先有蛋问题。您通常可以通过 setter 注入和某种 post 构造初始化来避免这种情况。
我认为您是通过扩展 DefaultBatchConfigurer
然后定义直接调用 DefaultBatchConfigurer
的 createJobRepository()
的 @Bean
注释方法 getJobLauncher()
造成这种情况的不确保 DataSource
首先在 DefaultBatchConfigurer
.
这完全没有必要,因为 DefaultBatchConfigurer
已经以正确的顺序为您创建了 JobRepository
、JobExplorer
和 JobLauncher
.
@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() );
}