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