#java #spring #spring-boot #spring-batch
#Ява #весна #пружинный ботинок #пружинная партия
Вопрос:
Я работаю над простым пакетным приложением Spring, и когда я закончил его настройку, я обнаружил эту проблему:
Зависимости некоторых компонентов в контексте приложения образуют цикл:
jobRestController, определенный в файле [/home/yassine/Downloads/demo/target/classes/com/example/demo/JobRestController.class] springBatchConfig, определенный в файле [/home/yassine/Downloads/demo/target/classes/com/example/demo/SpringBatchConfig.class]
Экшен:
Полагаться на циклические ссылки не рекомендуется, и по умолчанию они запрещены. Обновите приложение, чтобы удалить цикл зависимостей между компонентами. В крайнем случае, возможно, удастся автоматически прервать цикл, установив spring.main.allow-circular-ссылки на 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 ItemReaderlt;BankTransactiongt; bankTransactionItemReader; private ItemProcessorlt;BankTransaction, BankTransactiongt; bankTransactionItemProcessor; private ItemWriterlt;BankTransactiongt; bankTransactionItemWriter; @Bean public Job bankJob() { Step step1 = stepBuilderFactory.get("step-load-data") .lt;BankTransaction, BankTransactiongt;chunk(100) .reader(bankTransactionItemReader) .processor(bankTransactionItemProcessor) .writer(bankTransactionItemWriter) .build(); return jobBuilderFactory.get("bank-data-loader-job") .start(step1) .build(); } @Bean public FlatFileItemReaderlt;BankTransactiongt; flatFileItemReader(@Value("${inputFile}") Resource inputFile) { FlatFileItemReaderlt;BankTransactiongt; flatFileItemReader = new FlatFileItemReaderlt;gt;(); flatFileItemReader.setName("CSV-READER"); flatFileItemReader.setLinesToSkip(1); flatFileItemReader.setResource(inputFile); flatFileItemReader.setLineMapper(lineMapper()); return flatFileItemReader; } @Bean public LineMapperlt;BankTransactiongt; lineMapper() { DefaultLineMapperlt;BankTransactiongt; lineMapper = new DefaultLineMapperlt;gt;(); DelimitedLineTokenizer lineTokenizer = new DelimitedLineTokenizer(); lineTokenizer.setDelimiter(","); lineTokenizer.setStrict(false); lineTokenizer.setNames("id", "accountID", "strTransactionDate", "transactionType", "amount"); lineMapper.setLineTokenizer(lineTokenizer); BeanWrapperFieldSetMapperlt;BankTransactiongt; fieldSetMapper = new BeanWrapperFieldSetMapperlt;gt;(); 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 { Maplt;String, JobParametergt; parameters = new HashMaplt;gt;(); 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:
lt;?xml version="1.0" encoding="UTF-8"?gt; lt;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"gt; lt;modelVersiongt;4.0.0lt;/modelVersiongt; lt;parentgt; lt;groupIdgt;org.springframework.bootlt;/groupIdgt; lt;artifactIdgt;spring-boot-starter-parentlt;/artifactIdgt; lt;versiongt;2.6.1lt;/versiongt; lt;relativePath/gt; lt;!-- lookup parent from repository --gt; lt;/parentgt; lt;groupIdgt;com.examplelt;/groupIdgt; lt;artifactIdgt;demolt;/artifactIdgt; lt;versiongt;0.0.1-SNAPSHOTlt;/versiongt; lt;namegt;demolt;/namegt; lt;descriptiongt;demolt;/descriptiongt; lt;propertiesgt; lt;java.versiongt;11lt;/java.versiongt; lt;/propertiesgt; lt;dependenciesgt; lt;dependencygt; lt;groupIdgt;org.springframework.bootlt;/groupIdgt; lt;artifactIdgt;spring-boot-starter-batchlt;/artifactIdgt; lt;/dependencygt; lt;dependencygt; lt;groupIdgt;org.springframework.bootlt;/groupIdgt; lt;artifactIdgt;spring-boot-starter-data-jpalt;/artifactIdgt; lt;/dependencygt; lt;dependencygt; lt;groupIdgt;org.springframework.bootlt;/groupIdgt; lt;artifactIdgt;spring-boot-starter-weblt;/artifactIdgt; lt;/dependencygt; lt;dependencygt; lt;groupIdgt;org.springframework.bootlt;/groupIdgt; lt;artifactIdgt;spring-boot-devtoolslt;/artifactIdgt; lt;scopegt;runtimelt;/scopegt; lt;optionalgt;truelt;/optionalgt; lt;/dependencygt; lt;dependencygt; lt;groupIdgt;com.h2databaselt;/groupIdgt; lt;artifactIdgt;h2lt;/artifactIdgt; lt;scopegt;runtimelt;/scopegt; lt;/dependencygt; lt;dependencygt; lt;groupIdgt;org.projectlomboklt;/groupIdgt; lt;artifactIdgt;lomboklt;/artifactIdgt; lt;optionalgt;truelt;/optionalgt; lt;/dependencygt; lt;dependencygt; lt;groupIdgt;org.springframework.bootlt;/groupIdgt; lt;artifactIdgt;spring-boot-starter-testlt;/artifactIdgt; lt;scopegt;testlt;/scopegt; lt;/dependencygt; lt;dependencygt; lt;groupIdgt;org.springframework.batchlt;/groupIdgt; lt;artifactIdgt;spring-batch-testlt;/artifactIdgt; lt;scopegt;testlt;/scopegt; lt;/dependencygt; lt;/dependenciesgt; lt;buildgt; lt;pluginsgt; lt;plugingt; lt;groupIdgt;org.springframework.bootlt;/groupIdgt; lt;artifactIdgt;spring-boot-maven-pluginlt;/artifactIdgt; lt;configurationgt; lt;excludesgt; lt;excludegt; lt;groupIdgt;org.projectlomboklt;/groupIdgt; lt;artifactIdgt;lomboklt;/artifactIdgt; lt;/excludegt; lt;/excludesgt; lt;/configurationgt; lt;/plugingt; lt;/pluginsgt; lt;/buildgt; lt;/projectgt;
Я не смог это исправить, и я не нашел подобной проблемы в StackOverflow. Заранее спасибо
Комментарии:
1. Можете ли вы поделиться своим
pom.xml
контентом илиbuild.gradle
контентом?2. @chaitanyaguruprasad Я только что поделился этим, спасибо
3. Также, пожалуйста, опубликуйте свое сообщение об ошибке
4. @chaitanyaguruprasad да, я тоже опубликовал это в первой части, Зависимости некоторых компонентов в контексте приложения образуют цикл
Ответ №1:
сегодня у меня была та же проблема, и я решаю ее с помощью следующих шагов:
- вы должны создать ItemWriter,компоненты ItemProcessor
- объявите компонент задания в другом классе конфигурации
конфигурация весеннего пакета
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 FlatFileItemReaderlt;Persongt; getItemReader(@Value("${filePath}") Resource resource){ FlatFileItemReaderlt;Persongt; itemReader = new FlatFileItemReaderlt;Persongt;(); itemReader.setName("CSV-READER"); itemReader.setLinesToSkip(1); itemReader.setResource(resource); itemReader.setLineMapper(PersonLineMapper()); return itemReader; } @Bean public LineMapperlt;Persongt; PersonLineMapper(){ DefaultLineMapperlt;Persongt; lineMapper = new DefaultLineMapperlt;Persongt;(); DelimitedLineTokenizer lineTokenizer = new DelimitedLineTokenizer(); lineTokenizer.setStrict(false); lineTokenizer.setDelimiter(";"); lineTokenizer.setNames("id","fName","lName","strBirthDate","gender","dispo"); lineMapper.setLineTokenizer(lineTokenizer); BeanWrapperFieldSetMapperlt;Persongt; fieldSetMapper = new BeanWrapperFieldSetMapperlt;Persongt;(); fieldSetMapper.setTargetType(Person.class); lineMapper.setFieldSetMapper(fieldSetMapper); return lineMapper; } @Bean public ItemProcessorlt;Person, Persongt; getItemProcessor(){ return new ItemProcessorlt;Person, Persongt;() { 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 ItemWriterlt;Persongt; getItemWriter() { return new ItemWriterlt;Persongt;() { @Autowired private PersonRepository personRepository; @Override public void write(Listlt;? extends Persongt; 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 ItemReaderlt;Persongt; personItemReader; private final ItemWriterlt;Persongt; peronItemWriter; private final ItemProcessorlt;Person, Persongt; personItemProcessor; @Bean public Job personJob() { Step step1 = this.stepBuilderFactory.get("step-load-data") .lt;Person,Persongt;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{ Maplt;String, JobParametergt; parameters = new HashMaplt;gt;(); 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(); } }