应用上下文中一些bean的依赖在Spring Batch中形成了一个循环
Posted
技术标签:
【中文标题】应用上下文中一些bean的依赖在Spring Batch中形成了一个循环【英文标题】:The dependencies of some of the beans in the application context form a cycle in Spring Batch 【发布时间】:2022-01-09 06:12:40 【问题描述】:我正在开发一个简单的 Spring Batch 应用程序,当我完成配置后,我发现了这个问题:
应用上下文表单中一些bean的依赖关系 一个循环:
jobRestController 在文件中定义 [/home/yassine/Downloads/demo/target/classes/com/example/demo/JobRestController.class] springBatchConfig 在文件中定义 [/home/yassine/Downloads/demo/target/classes/com/example/demo/SpringBatchConfig.class]
行动:
不鼓励依赖循环引用,它们是 默认禁止。更新您的应用程序以删除 bean之间的依赖循环。作为最后的手段,可能 通过设置自动中断循环 spring.main.allow-circular-references 为 true。
两个类的实现:
SpringBatchConfig:
import lombok.AllArgsConstructor;
import org.springframework.batch.core.Job;
import org.springframework.batch.core.Step;
import org.springframework.batch.core.configuration.annotation.EnableBatchProcessing;
import org.springframework.batch.core.configuration.annotation.JobBuilderFactory;
import org.springframework.batch.core.configuration.annotation.StepBuilderFactory;
import org.springframework.batch.item.ItemProcessor;
import org.springframework.batch.item.ItemReader;
import org.springframework.batch.item.ItemWriter;
import org.springframework.batch.item.file.FlatFileItemReader;
import org.springframework.batch.item.file.LineMapper;
import org.springframework.batch.item.file.mapping.BeanWrapperFieldSetMapper;
import org.springframework.batch.item.file.mapping.DefaultLineMapper;
import org.springframework.batch.item.file.transform.DelimitedLineTokenizer;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.Resource;
@Configuration
@EnableBatchProcessing
@AllArgsConstructor
public class SpringBatchConfig
private JobBuilderFactory jobBuilderFactory;
private StepBuilderFactory stepBuilderFactory;
private ItemReader<BankTransaction> bankTransactionItemReader;
private ItemProcessor<BankTransaction, BankTransaction> bankTransactionItemProcessor;
private ItemWriter<BankTransaction> bankTransactionItemWriter;
@Bean
public Job bankJob()
Step step1 = stepBuilderFactory.get("step-load-data")
.<BankTransaction, BankTransaction>chunk(100)
.reader(bankTransactionItemReader)
.processor(bankTransactionItemProcessor)
.writer(bankTransactionItemWriter)
.build();
return jobBuilderFactory.get("bank-data-loader-job")
.start(step1)
.build();
@Bean
public FlatFileItemReader<BankTransaction> flatFileItemReader(@Value("$inputFile") Resource inputFile)
FlatFileItemReader<BankTransaction> flatFileItemReader = new FlatFileItemReader<>();
flatFileItemReader.setName("CSV-READER");
flatFileItemReader.setLinesToSkip(1);
flatFileItemReader.setResource(inputFile);
flatFileItemReader.setLineMapper(lineMapper());
return flatFileItemReader;
@Bean
public LineMapper<BankTransaction> lineMapper()
DefaultLineMapper<BankTransaction> lineMapper = new DefaultLineMapper<>();
DelimitedLineTokenizer lineTokenizer = new DelimitedLineTokenizer();
lineTokenizer.setDelimiter(",");
lineTokenizer.setStrict(false);
lineTokenizer.setNames("id", "accountID", "strTransactionDate", "transactionType", "amount");
lineMapper.setLineTokenizer(lineTokenizer);
BeanWrapperFieldSetMapper<BankTransaction> fieldSetMapper = new BeanWrapperFieldSetMapper<>();
fieldSetMapper.setTargetType(BankTransaction.class);
lineMapper.setFieldSetMapper(fieldSetMapper);
return lineMapper;
JobRestController:
import lombok.AllArgsConstructor;
import org.springframework.batch.core.*;
import org.springframework.batch.core.launch.JobLauncher;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.HashMap;
import java.util.Map;
@RestController
@AllArgsConstructor
public class JobRestController
private JobLauncher jobLauncher;
private Job job;
@GetMapping("/startJob")
public BatchStatus load() throws Exception
Map<String, JobParameter> parameters = new HashMap<>();
parameters.put("time", new JobParameter(System.currentTimeMillis()));
JobParameters jobParameters = new JobParameters(parameters);
JobExecution jobExecution = jobLauncher.run(job, jobParameters);
while (jobExecution.isRunning())
System.out.println(".....");
return jobExecution.getStatus();
pom.xml:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.6.1</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.example</groupId>
<artifactId>demo</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>demo</name>
<description>demo</description>
<properties>
<java.version>11</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-batch</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.batch</groupId>
<artifactId>spring-batch-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<excludes>
<exclude>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</exclude>
</excludes>
</configuration>
</plugin>
</plugins>
</build>
</project>
我无法修复它,我在 *** 上也没有发现任何类似的问题。提前谢谢你
【问题讨论】:
您能分享您的pom.xml
或build.gradle
内容吗?
@chaitanyaguruprasad 我刚刚分享了,谢谢
另外请发布您的错误信息
@chaitanyaguruprasad 是的,我在第一部分也发布了,应用程序上下文中一些 bean 的依赖关系形成一个循环
【参考方案1】:
今天我遇到了同样的问题,我通过以下步骤解决了它:
-
你应该创建 ItemWriter,ItemProcessor Beans
在另一个配置类中声明 Job bean
春季批处理配置
package com.example.demo.config;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.List;
import org.springframework.batch.core.configuration.annotation.EnableBatchProcessing;
import org.springframework.batch.item.ItemProcessor;
import org.springframework.batch.item.ItemWriter;
import org.springframework.batch.item.file.FlatFileItemReader;
import org.springframework.batch.item.file.LineMapper;
import org.springframework.batch.item.file.mapping.BeanWrapperFieldSetMapper;
import org.springframework.batch.item.file.mapping.DefaultLineMapper;
import org.springframework.batch.item.file.transform.DelimitedLineTokenizer;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.Resource;
import com.example.demo.dao.Person;
import com.example.demo.dao.PersonRepository;
import lombok.RequiredArgsConstructor;
@Configuration
@EnableBatchProcessing
@RequiredArgsConstructor
public class SpringBatchConfig
@Bean
public FlatFileItemReader<Person> getItemReader(@Value("$filePath") Resource resource)
FlatFileItemReader<Person> itemReader = new FlatFileItemReader<Person>();
itemReader.setName("CSV-READER");
itemReader.setLinesToSkip(1);
itemReader.setResource(resource);
itemReader.setLineMapper(PersonLineMapper());
return itemReader;
@Bean
public LineMapper<Person> PersonLineMapper()
DefaultLineMapper<Person> lineMapper = new DefaultLineMapper<Person>();
DelimitedLineTokenizer lineTokenizer = new DelimitedLineTokenizer();
lineTokenizer.setStrict(false);
lineTokenizer.setDelimiter(";");
lineTokenizer.setNames("id","fName","lName","strBirthDate","gender","dispo");
lineMapper.setLineTokenizer(lineTokenizer);
BeanWrapperFieldSetMapper<Person> fieldSetMapper = new BeanWrapperFieldSetMapper<Person>();
fieldSetMapper.setTargetType(Person.class);
lineMapper.setFieldSetMapper(fieldSetMapper);
return lineMapper;
@Bean
public ItemProcessor<Person, Person> getItemProcessor()
return new ItemProcessor<Person, Person>()
private DateFormat dateFormat = new SimpleDateFormat("dd/MM/yyyy");
@Override
public Person process(Person item) throws Exception
item.setBirthDate(dateFormat.parse(item.getStrBirthDate()));
return item;
;
@Bean
public ItemWriter<Person> getItemWriter()
return new ItemWriter<Person>()
@Autowired
private PersonRepository personRepository;
@Override
public void write(List<? extends Person> items) throws Exception
personRepository.saveAll(items);
;
工作配置
package com.example.demo.config;
import org.springframework.batch.core.Job;
import org.springframework.batch.core.Step;
import org.springframework.batch.core.configuration.annotation.JobBuilderFactory;
import org.springframework.batch.core.configuration.annotation.StepBuilderFactory;
import org.springframework.batch.item.ItemProcessor;
import org.springframework.batch.item.ItemReader;
import org.springframework.batch.item.ItemWriter;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import com.example.demo.dao.Person;
import lombok.RequiredArgsConstructor;
@Configuration
@RequiredArgsConstructor
public class JobConfig
private final JobBuilderFactory jobBuilderFactory;
private final StepBuilderFactory stepBuilderFactory;
private final ItemReader<Person> personItemReader;
private final ItemWriter<Person> peronItemWriter;
private final ItemProcessor<Person, Person> personItemProcessor;
@Bean
public Job personJob()
Step step1 = this.stepBuilderFactory.get("step-load-data")
.<Person,Person>chunk(100)
.writer(peronItemWriter)
.reader(personItemReader)
.processor(personItemProcessor)
.build();
return this.jobBuilderFactory.get("person-data-loader-job")
.start(step1)
.build();
用于启动作业的休息控制器
package com.example.demo.web;
import java.util.HashMap;
import java.util.Map;
import org.springframework.batch.core.BatchStatus;
import org.springframework.batch.core.Job;
import org.springframework.batch.core.JobExecution;
import org.springframework.batch.core.JobParameter;
import org.springframework.batch.core.JobParameters;
import org.springframework.batch.core.launch.JobLauncher;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import lombok.RequiredArgsConstructor;
@RestController
@RequiredArgsConstructor
public class PersonRestController
private final JobLauncher jobLauncher;
private final Job job;
@GetMapping("/startBatch")
public BatchStatus load() throws Exception
Map<String, JobParameter> parameters = new HashMap<>();
parameters.put("time", new JobParameter(System.currentTimeMillis()));
JobParameters jobParameters = new JobParameters(parameters);
JobExecution jobExecution = jobLauncher.run(job, jobParameters);
while(jobExecution.isRunning())
System.out.println("....");
return jobExecution.getStatus();
【讨论】:
以上是关于应用上下文中一些bean的依赖在Spring Batch中形成了一个循环的主要内容,如果未能解决你的问题,请参考以下文章