Introduction à Spring Batch

1. Introduction

Dans cet article, nous allons nous concentrer sur une introduction pratique et axée sur le code à Spring Batch. Spring Batch est un cadre de traitement conçu pour une exécution robuste des travaux.

Il s'agit de la version 3.0 actuelle, qui prend en charge Spring 4 et Java 8. Il prend également en charge JSR-352, qui est une nouvelle spécification Java pour le traitement par lots.

Voici quelques cas d'utilisation intéressants et pratiques du framework.

2. Principes de base du workflow

Spring batch suit l'architecture par lots traditionnelle dans laquelle un référentiel de travaux effectue le travail de planification et d'interaction avec le travail.

Un travail peut comporter plusieurs étapes - et chaque étape suit généralement la séquence de lecture des données, de leur traitement et de leur écriture.

Et bien sûr, le framework fera la plupart du gros du travail pour nous ici - en particulier en ce qui concerne le travail de persistance de bas niveau de traitement des tâches - en utilisant sqlite pour le référentiel de tâches.

2.1. Notre exemple d'utilisation

Le cas d'utilisation simple que nous allons aborder ici est le suivant: nous allons migrer certaines données de transactions financières de CSV vers XML.

Le fichier d'entrée a une structure très simple - il contient une transaction par ligne, composée de: un nom d'utilisateur, l'identifiant de l'utilisateur, la date de la transaction et le montant:

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. Le Maven POM

Les dépendances requises pour ce projet sont spring core, spring batch et sqlite jdbc connector:

   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. Configuration du lot de printemps

La première chose que nous ferons est de configurer Spring Batch avec XML:

Bien entendu, une configuration Java est également disponible:

@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. Configuration du travail par lots de printemps

Écrivons maintenant notre description de poste pour le travail CSV vers XML:

                           com.baeldung.spring_batch_intro.model.Transaction           

Et bien sûr, la configuration de travail similaire basée sur 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(); } }

OK, maintenant que nous avons toute la configuration, décomposons-la et commençons à en discuter.

5.1. Lire des données et créer des objets avec ItemReader

Nous avons d'abord configuré le cvsFileItemReader qui lira les données de record.csv et les convertira en objet 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 + "]"; } }

Pour ce faire, il utilise un mappeur personnalisé:

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. Traitement des données avec ItemProcessor

Nous avons créé notre propre processeur d'articles, CustomItemProcessor . Cela ne traite rien lié à l'objet de transaction - il ne fait que transmettre l'objet d'origine du lecteur à l'écrivain:

public class CustomItemProcessor implements ItemProcessor { public Transaction process(Transaction item) { return item; } }

5.3. Ecrire des objets sur le FS avec ItemWriter

Enfin, nous allons stocker cette transaction dans un fichier xml situé dans xml / output.xml :

5.4. Configuration du travail par lots

Donc, tout ce que nous avons à faire est de relier les points à un travail - en utilisant la syntaxe batch: job .

Notez l' intervalle de validation - c'est le nombre de transactions à conserver en mémoire avant de valider le lot dans itemWriter ; il gardera les transactions en mémoire jusqu'à ce point (ou jusqu'à ce que la fin des données d'entrée soit rencontrée):

5.5. Exécution du travail par lots

C'est tout - configurons et exécutons maintenant tout:

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. Conclusion

Ce didacticiel vous donne une idée de base sur la façon de travailler avec Spring Batch et de l'utiliser dans un cas d'utilisation simple.

Il montre comment vous pouvez facilement développer votre pipeline de traitement par lots et comment personnaliser les différentes étapes de lecture, de traitement et d'écriture.

L' implémentation complète de ce didacticiel se trouve dans le projet github - il s'agit d'un projet basé sur Eclipse, il devrait donc être facile à importer et à exécuter tel quel.