Введение в Spring Batch
1. Вступление
В этой статье мы сосредоточимся на практическом введении в Spring Batch, ориентированном на код. Spring Batch - это среда обработки, разработанная для надежного выполнения заданий.
Это текущая версия 3.0, которая поддерживает Spring 4 и Java 8. Он также поддерживает JSR-352, новую спецификацию Java для пакетной обработки.
Here are несколько интересных и практических примеров использования фреймворка.
2. Основы рабочего процесса
Spring batch следует традиционной пакетной архитектуре, в которой репозиторий заданий выполняет планирование и взаимодействие с заданием.
Задание может иметь более одного шага - и каждый шаг обычно следует последовательности чтения данных, их обработки и записи.
И, конечно же, фреймворк возьмет на себя здесь большую часть тяжелой работы - особенно когда дело доходит до работы на низком уровне персистентности по работе с заданиями - используяsqlite для репозитория заданий.
2.1. Наш пример использования
Вот простой пример использования: мы собираемся перенести некоторые данные финансовых транзакций из CSV в XML.
Входной файл имеет очень простую структуру - он содержит транзакцию на строку, состоящую из: имени пользователя, идентификатора пользователя, даты транзакции и суммы:
username, userid, transaction_date, transaction_amount
devendra, 1234, 31/10/2015, 10000
john, 2134, 3/12/2015, 12321
robin, 2134, 2/02/2015, 23411
3. Maven POM
Для этого проекта требуются следующие зависимости: ядро пружины, пакет пружин и соединитель jdbcsqlite:
4.0.0
org.example
spring-batch-intro
0.1-SNAPSHOT
jar
spring-batch-intro
http://maven.apache.org
UTF-8
4.2.0.RELEASE
3.0.5.RELEASE
3.8.11.2
org.xerial
sqlite-jdbc
${sqlite.version}
org.springframework
spring-oxm
${spring.version}
org.springframework
spring-jdbc
${spring.version}
org.springframework.batch
spring-batch-core
${spring.batch.version}
4. Пакетная конфигурация Spring
Первым делом мы настроим Spring Batch с XML:
Конечно, конфигурация Java также доступна:
@Configuration
@EnableBatchProcessing
public class SpringConfig {
@Value("org/springframework/batch/core/schema-drop-sqlite.sql")
private Resource dropReopsitoryTables;
@Value("org/springframework/batch/core/schema-sqlite.sql")
private Resource dataReopsitorySchema;
@Bean
public DataSource dataSource() {
DriverManagerDataSource dataSource = new DriverManagerDataSource();
dataSource.setDriverClassName("org.sqlite.JDBC");
dataSource.setUrl("jdbc:sqlite:repository.sqlite");
return dataSource;
}
@Bean
public DataSourceInitializer dataSourceInitializer(DataSource dataSource)
throws MalformedURLException {
ResourceDatabasePopulator databasePopulator =
new ResourceDatabasePopulator();
databasePopulator.addScript(dropReopsitoryTables);
databasePopulator.addScript(dataReopsitorySchema);
databasePopulator.setIgnoreFailedDrops(true);
DataSourceInitializer initializer = new DataSourceInitializer();
initializer.setDataSource(dataSource);
initializer.setDatabasePopulator(databasePopulator);
return initializer;
}
private JobRepository getJobRepository() throws Exception {
JobRepositoryFactoryBean factory = new JobRepositoryFactoryBean();
factory.setDataSource(dataSource());
factory.setTransactionManager(getTransactionManager());
factory.afterPropertiesSet();
return (JobRepository) factory.getObject();
}
private PlatformTransactionManager getTransactionManager() {
return new ResourcelessTransactionManager();
}
public JobLauncher getJobLauncher() throws Exception {
SimpleJobLauncher jobLauncher = new SimpleJobLauncher();
jobLauncher.setJobRepository(getJobRepository());
jobLauncher.afterPropertiesSet();
return jobLauncher;
}
}
5. Конфигурация пакетного задания Spring
Давайте теперь напишем описание нашей работы для работы с CSV в XML:
org.example.spring_batch_intro.model.Transaction
И, конечно, похожий конфиг работы на основе Java:
public class SpringBatchConfig {
@Autowired
private JobBuilderFactory jobs;
@Autowired
private StepBuilderFactory steps;
@Value("input/record.csv")
private Resource inputCsv;
@Value("file:xml/output.xml")
private Resource outputXml;
@Bean
public ItemReader itemReader()
throws UnexpectedInputException, ParseException {
FlatFileItemReader reader = new FlatFileItemReader();
DelimitedLineTokenizer tokenizer = new DelimitedLineTokenizer();
String[] tokens = { "username", "userid", "transactiondate", "amount" };
tokenizer.setNames(tokens);
reader.setResource(inputCsv);
DefaultLineMapper lineMapper =
new DefaultLineMapper();
lineMapper.setLineTokenizer(tokenizer);
lineMapper.setFieldSetMapper(new RecordFieldSetMapper());
reader.setLineMapper(lineMapper);
return reader;
}
@Bean
public ItemProcessor itemProcessor() {
return new CustomItemProcessor();
}
@Bean
public ItemWriter itemWriter(Marshaller marshaller)
throws MalformedURLException {
StaxEventItemWriter itemWriter =
new StaxEventItemWriter();
itemWriter.setMarshaller(marshaller);
itemWriter.setRootTagName("transactionRecord");
itemWriter.setResource(outputXml);
return itemWriter;
}
@Bean
public Marshaller marshaller() {
Jaxb2Marshaller marshaller = new Jaxb2Marshaller();
marshaller.setClassesToBeBound(new Class[] { Transaction.class });
return marshaller;
}
@Bean
protected Step step1(ItemReader reader,
ItemProcessor processor,
ItemWriter writer) {
return steps.get("step1"). chunk(10)
.reader(reader).processor(processor).writer(writer).build();
}
@Bean(name = "firstBatchJob")
public Job job(@Qualifier("step1") Step step1) {
return jobs.get("firstBatchJob").start(step1).build();
}
}
Итак, теперь, когда у нас есть вся конфигурация, давайте разберем ее и начнем обсуждать.
5.1. Чтение данных и создание объектов с помощьюItemReader
Сначала мы настроилиcvsFileItemReader, который будет читать данные изrecord.csv и преобразовывать их в объектTransaction:
@SuppressWarnings("restriction")
@XmlRootElement(name = "transactionRecord")
public class Transaction {
private String username;
private int userId;
private Date transactionDate;
private double amount;
/* getters and setters for the attributes */
@Override
public String toString() {
return "Transaction [username=" + username + ", userId=" + userId
+ ", transactionDate=" + transactionDate + ", amount=" + amount
+ "]";
}
}
Для этого он использует собственный маппер:
public class RecordFieldSetMapper implements FieldSetMapper {
public Transaction mapFieldSet(FieldSet fieldSet) throws BindException {
SimpleDateFormat dateFormat = new SimpleDateFormat("dd/MM/yyyy");
Transaction transaction = new Transaction();
transaction.setUsername(fieldSet.readString("username"));
transaction.setUserId(fieldSet.readInt(1));
transaction.setAmount(fieldSet.readDouble(3));
String dateString = fieldSet.readString(2);
try {
transaction.setTransactionDate(dateFormat.parse(dateString));
} catch (ParseException e) {
e.printStackTrace();
}
return transaction;
}
}
5.2. Обработка данных сItemProcessor
Мы создали собственный обработчик элементов,CustomItemProcessor. Это не обрабатывает ничего, связанного с объектом транзакции - все, что он делает, это передает исходный объект, поступающий от читателя, к писателю:
public class CustomItemProcessor implements ItemProcessor {
public Transaction process(Transaction item) {
return item;
}
}
5.3. Запись объектов в FS с помощьюItemWriter
Наконец, мы собираемся сохранить этотtransaction в xml-файле, расположенном вxml/output.xml:
5.4. Настройка пакетного задания
Итак, все, что нам нужно сделать, это соединить точки с заданием - используя синтаксисbatch:job.
Обратите внимание наcommit-interval - это количество транзакций, которые должны храниться в памяти перед фиксацией пакета вitemWriter; он будет удерживать транзакции в памяти до этой точки (или до тех пор, пока не встретится конец входных данных):
5.5. Запуск пакетного задания
Вот и все - давайте настроим и запустим все:
public class App {
public static void main(String[] args) {
// Spring Java config
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
context.register(SpringConfig.class);
context.register(SpringBatchConfig.class);
context.refresh();
JobLauncher jobLauncher = (JobLauncher) context.getBean("jobLauncher");
Job job = (Job) context.getBean("firstBatchJob");
System.out.println("Starting the batch job");
try {
JobExecution execution = jobLauncher.run(job, new JobParameters());
System.out.println("Job Status : " + execution.getStatus());
System.out.println("Job completed");
} catch (Exception e) {
e.printStackTrace();
System.out.println("Job failed");
}
}
}
6. Заключение
Это руководство дает вам общее представление оhow to work with Spring Batch и о том, как его использовать в простом сценарии использования.
Он показывает, как вы можете легко разработать конвейер пакетной обработки и как настроить различные этапы чтения, обработки и записи.
full implementation этого руководства можно найти вthe github project - это проект на основе Eclipse, поэтому его должно быть легко импортировать и запускать как есть.