Doposud jsem v příspěvcích k Spring Batch používal xml konfiguraci. Spring ale umožňuje též konfigurovat pomocí java tříd. V tomto příspěvku ukáži jednoduchý Spring Batch projekt, který bude používat java config. Projekt bude stejný jako v tomto příspěvku, pouze bude místo xml používat java konfiguraci.
Struktura projektu
│ pom.xml │ └───src ├───main │ └───java │ └───batch │ AppConfig.java │ Employee.java │ ExecuteBatchJob.java │ ResultWriter.java │ └───resources reportCS.csv
AppConfig.java předstaje java třídu obsahující konfiguraci.
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.ItemReader; 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.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.core.io.ClassPathResource; @Configuration @EnableBatchProcessing public class AppConfig { @Autowired public JobBuilderFactory jobBuilderFactory; @Autowired public StepBuilderFactory stepBuilderFactory; @Bean public Job myJob() { return jobBuilderFactory.get("myJob") .start(myStep()) .build(); } @Bean public Step myStep() { return stepBuilderFactory.get("myStep") .<Employee, Employee> chunk(2) .reader(csvReader()) .writer(resultWriter()) .build(); } @Bean public ItemReader<Employee> csvReader() { FlatFileItemReader<Employee> reader = new FlatFileItemReader<Employee>(); reader.setResource(new ClassPathResource("reportCS.csv")); reader.setEncoding("UTF-8"); reader.setLinesToSkip(1); reader.setLineMapper(lineMapper()); return reader; } @Bean public LineMapper<Employee> lineMapper() { DefaultLineMapper<Employee> lineMapper = new DefaultLineMapper<Employee>(); // create line tokenizer DelimitedLineTokenizer lineTokenizer = new DelimitedLineTokenizer(); lineTokenizer.setNames(new String[] {"Name", "Surname", "Location", "Job", "Earning"}); lineMapper.setLineTokenizer(lineTokenizer); // create field set mapper BeanWrapperFieldSetMapper<Employee> fieldSetMapper = new BeanWrapperFieldSetMapper<Employee>(); fieldSetMapper.setTargetType(Employee.class); lineMapper.setFieldSetMapper(fieldSetMapper); return lineMapper; } @Bean public ResultWriter resultWriter() { return new ResultWriter(); } }
Spring anotace @Configuration
naznačuje, že tato třída obsahuje definici jedné nebo více bean. Anotace @EnableBatchProcessing
provádí základní konfiguraci batche. Tato anotace například zajistí autowirování JobBuilderFactory
a StepBuilderFactory
. Anotace @Bean
označuje metodu, která vytváří beanu pro Spring kontejner. Tato anotace odpovídá xml elementu <bean></bean>
.
Tato část jobBuilderFactory.get("myJob").start(myStep()).build();
vytváří Job
s názvem „myJob“, který obsahuje jeden Step
, který se získá voláním metody myStep().
Tato část stepBuilderFactory.get("myStep").<Employee, Employee> chunk(2).reader(csvReader()).writer(resultWriter()).build();
vytváří Step
s názvem „myStep“, který obsahuje Chunk
s commit intervalem 2. Tento chunk má definovaný ItemReader, který vrací metoda csvReader() a ItemWriter, který vrací metoda resultWriter().
Employee.java
public class Employee { private String name; private String surname; private String location; private String job; private String earning; // setters and getters }
ResultWriter.java
import java.util.List; import org.springframework.batch.item.ItemWriter; public class ResultWriter implements ItemWriter<Employee>{ public void write(List<? extends Employee> items) throws Exception { System.out.println("Writing"); for (Employee item : items) { System.out.println(item.getSurname() + "\t" + item.getEarning()); } } }
ExecuteBatchJob.java
import org.springframework.batch.core.Job; import org.springframework.batch.core.JobExecution; import org.springframework.batch.core.JobParameters; import org.springframework.batch.core.launch.JobLauncher; import org.springframework.context.annotation.AnnotationConfigApplicationContext; public class ExecuteBatchJob { public static void main(String[] args) { AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class); JobLauncher jobLauncher = (JobLauncher) context.getBean("jobLauncher"); Job job = (Job) context.getBean("myJob"); try { JobExecution execution = jobLauncher.run(job, new JobParameters()); } catch (Exception e) { e.printStackTrace(); } finally { context.close(); } } }
Narozdíl od xml konfigurace, kde se context vytváří takto ApplicationContext context = new ClassPathXmlApplicationContext("config.xml");
se v případě java konfigurace používá AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
, které se jako parametr předá třída s konfigurací.
Pro úplnost ještě soubor reportCS.csv
Name,Surname,Location,Job,Earning Václav,Zelený,Čáslav,skladník,22000 Jana,Skočdopolová,Praha,účetní,27900 Jiří,Nohavička,Aš,prodavač,19000 Jan,Starý,Náměšť nad Oslavou,manažer,33000 Tereza,Nová,Benešov,kuchařka,14000
Výsledek spuštění
Writing Zelený 22000 Skočdopolová 27900 Writing Nohavička 19000 Starý 33000 Writing Nová 14000