1. Въведение
В тази статия ще се съсредоточим върху практично въведение в Spring Batch, фокусирано върху кода. Spring Batch е рамка за обработка, предназначена за стабилно изпълнение на задачите.
Това е текущата версия 3.0, която поддържа Spring 4 и Java 8. Той също така побира JSR-352, което е нова спецификация на Java за групова обработка.
Ето няколко интересни и практични случая на използване на рамката.
2. Основи на работния процес
Spring batch следва традиционната 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
Зависимостите, необходими за този проект, са пружинно ядро, пролетна партида и sqlite jdbc конектор:
org.xerial sqlite-jdbc 3.15.1 org.springframework spring-oxm 5.2.0.RELEASE org.springframework spring-jdbc 5.2.0.RELEASE org.springframework.batch spring-batch-core 4.2.0.RELEASE
4. Spring Batch Config
Първото нещо, което ще направим, е да конфигурираме 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. Конфигурация за пролетна партидна работа
Нека сега напишем нашата длъжностна характеристика за CSV към XML работа:
com.baeldung.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 LocalDateTime 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 { DateTimeFormatter formatter = DateTimeFormatter.ofPattern("d/M/yyy"); Transaction transaction = new Transaction(); transaction.setUsername(fieldSet.readString("username")); transaction.setUserId(fieldSet.readInt(1)); transaction.setAmount(fieldSet.readDouble(3)); String dateString = fieldSet.readString(2); transaction.setTransactionDate(LocalDate.parse(dateString, formatter).atStartOfDay()); return transaction; } }
5.2. Обработка на данни с ItemProcessor
Създадохме наш собствен процесор за обработка на артикули, CustomItemProcessor . Това не обработва нищо, свързано с обекта на транзакцията - всичко, което прави, е да предаде оригиналния обект, идващ от четеца, на писателя:
public class CustomItemProcessor implements ItemProcessor { public Transaction process(Transaction item) { return item; } }
5.3. Писане на обекти във FS с ItemWriter
Накрая ще съхраним тази транзакция в xml файл, намиращ се на xml / output.xml :
5.4. Конфигуриране на пакетното задание
Така че всичко, което трябва да направим, е да свържем точките със задача - използвайки синтаксиса batch: job .
Обърнете внимание на интервала на фиксиране - това е броят на транзакциите, които трябва да се запазят в паметта, преди да се ангажира партидата към 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. Заключение
Този урок ви дава основна идея за това как да работите с Spring Batch и как да го използвате в проста употреба.
Той показва как можете лесно да разработите своя конвейер за групова обработка и как можете да персонализирате различни етапи в четенето, обработката и писането.
Най- пълното прилагане на този урок може да се намери в проекта GitHub - това е Eclipse проект на базата, така че трябва да бъде лесен за внос и работи като такъв.