Spring & Batch
Octobre 2017
M. Mohamed
2Copyright © 2017 Capgemini. Tous droits réservés
CSD | Octobre 2017
Plan & Objectifs
Plan
1. Un tour au pays de Spring & Spring-Boot
2. C’est quoi un Batch et Spring-Batch ?
3. Comment cela fonctionne ?
4. Notions avancées et applications.
5. Un bon exemple de la vrai vie.
Objectifs
1. Assimiler Spring-Batch
2. Détecter les cas d’usages
3. Pouvoir faire du Batch et aller encore plus loin avec…
Bonjour « Spring Framework »…
4Copyright © 2017 Capgemini. Tous droits réservés
CSD | Octobre 2017
Spring Framework (Le Cœur 1/3)
Framework Java open-source créé en 2003 par « Pivotal Software »
Un conteneur léger (contrairement aux EJBs)
S’appui essentiellement sur l’injection de dépendance et l’AOP
Intégration facile d’autre Framework (Hibernate , JSF, Thymeleaf ,…)
5Copyright © 2017 Capgemini. Tous droits réservés
CSD | Octobre 2017
Spring Framework (Le Boot 2/3)
Peu de configuration (auto-configurable tant que c’est possible)
Application Runnable , autonome même en production.
Embarque même un Tomcat (+ Jetty) , plus besoin du War
Plus besoin des fichiers XML (context.xml, web.xml, …) @annotations
6Copyright © 2017 Capgemini. Tous droits réservés
CSD | Octobre 2017
Spring Framework (La tendance 3/3 @GoogleTrend)
C’est quoi un « Batch » ?
8Copyright © 2017 Capgemini. Tous droits réservés
CSD | Octobre 2017
Batch (C’est quoi ? 1/2)
Traitement de données par lots successifs
 Gros volumes de données
Plusieurs opérations s'enchainent pour chaque lot
Déclenchement automatique ou manuel
9Copyright © 2017 Capgemini. Tous droits réservés
CSD | Octobre 2017
Batch (Par l’exemple 2/2)
Un exemple concret : import des commandes journalières
Lecture d’un lot
de commandes
depuis un fichier
Vérification des
commandes
Sauvegarde du
lot de
commandes
dans le ST
Répéter ce cycle pour chaque lot de commandes jusqu’à la dernière
Déclencher par CRON, tous les jours à 5H, avant l’arrivée des collaborateurs
10Copyright © 2017 Capgemini. Tous droits réservés
CSD | Octobre 2017
Spring-Batch (C’est quoi encore ? 1/6)
Framework open-source pour le Batch Processing
Application Batch robuste (Entreprise application)
Des fonctions réutilisables pour le traitement des données
Ajoute une approche standard pour définir les Jobs Batch
11Copyright © 2017 Capgemini. Tous droits réservés
CSD | Octobre 2017
Spring-Batch (En plus 2/6)
La gestion des transactions (Commit interval & Rollback)
Traitement par lot facilement (Chuncked process)
Gestion des erreurs, de la reprise et l’arrêt des Jobs
Le tous dans Spring…
12Copyright © 2017 Capgemini. Tous droits réservés
CSD | Octobre 2017
Spring-Batch (le concept 3/6)
Un Job est défini par un Flow de Step (un ou plusieurs)
Un Step définie généralement un Reader, un Processor et Writer
Un Step peut définir aussi un simple Tasklet
Un référentiel de Job (JobRepository) et un exécuteur de Job
(JobLauncher)
Source : Spring.io
13Copyright © 2017 Capgemini. Tous droits réservés
CSD | Octobre 2017
Spring-Batch (le fonctionnement 4/6)
Le Reader lit un élément à la fois
Le Processor traite un élément à la fois
Quand le lot est lu et traité, le Writer l’écrit
Source : Spring.io
14Copyright © 2017 Capgemini. Tous droits réservés
CSD | Octobre 2017
Spring-Batch (Notions avancées 5/6)
Flow de Step séquentiel, conditionnel ou parallèle
Traitement parallèle (Split Flow) et Multi-threading
Des Listeners (StepExecutionListener, ChunkListener, ItemReadListener,…)
Gestions intégrée des exceptions
15Copyright © 2017 Capgemini. Tous droits réservés
CSD | Octobre 2017
Spring-Batch (Diagramme 6/6)
Source : Cépria FR
16Copyright © 2017 Capgemini. Tous droits réservés
CSD | Octobre 2017
Par l’exemple
comme dans la vrai vie …
17Copyright © 2017 Capgemini. Tous droits réservés
CSD | Octobre 2017
Exemple d’usage (Contexte 1/8)
Application Web pouvant faire appel à des Jobs via l’IHM
Suivre le statut des Jobs
Permettre de jouer les Jobs en Synchrone et en Asynchrone
Trois Jobs, un premier pour importer des fichiers CSV en Base de
données, un deuxième pour exporter les données en fichier JSON et un
dernier Job pour faire l’import et l’export d’un grand volume de données
(200 000 lignes) en moins de 10 minutes
18Copyright © 2017 Capgemini. Tous droits réservés
CSD | Octobre 2017
Exemple d’usage (Besoin métier 2/8)
Import Job :
• Input : un fichier CSV contenant les informations des employées et leurs
salaires brutes annuels
• Output : les informations transformées et les taxes calculées et
enregistrées dans la base de donnés
Export Job :
• Input : les informations des employées et les taxes calculées et
enregistrées dans la base de donnés
• Output : un fichier JSON contenant toutes les données.
PLUS : une API REST pour effectuer le calcule des taxes et la validation
19Copyright © 2017 Capgemini. Tous droits réservés
CSD | Octobre 2017
Exemple d’usage (Architecture & choix techniques 3/8)
Utilisation du Spring-Boot avec Spring-MVC et Srping-Batch
Intégration du Thymeleaf comme moteur de Templating (+ nekohtml)
MySQL Driver, Mokito pour les tests et Jackson pour le support du JSON
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
…
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-batch</artifactId>
…
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
…
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
…
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
…
<groupId>net.sourceforge.nekohtml</groupId>
<artifactId>nekohtml</artifactId>
…
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
20Copyright © 2017 Capgemini. Tous droits réservés
CSD | Octobre 2017
Exemple d’usage (Diagramme de la solution 4/8)
21Copyright © 2017 Capgemini. Tous droits réservés
CSD | Octobre 2017
Exemple d’usage (Code source 5/8)
Une interface est disponible pour définir un Tasklet
public interface ItemReader<T> {
T read() throws Exception, UnexpectedInputException , ParseException;
}
public interface ItemWriter<T> {
void write(List<? extends T> items) throws Exception;
}
public interface ItemProcessor<I, O> {
O process(I item) throws Exception;
}
Trois interfaces sont disponibles pour définir un Reader, Processor et Writer
public interface Tasklet {
RepeatStatus execute(StepContribution contribution, ChunkContext chunkContext) throws Exception
}
Une interface est disponible pour définir un Partionner
public interface Partitioner {
Map<String, ExecutionContext> partition(int gridSize);
}
22Copyright © 2017 Capgemini. Tous droits réservés
CSD | Octobre 2017
Exemple d’usage (Un Job par annotation 6/8)
@Bean
public ItemReader<Person> reader() {
return new PersonReaderFromFile();
}
@Bean
public ImportPersonItemProcessor processor() {
return new ImportPersonItemProcessor();
}
@Bean
public ItemWriter<Person> writer() {
return new PersonWriterToDataBase();
}
@Bean
public Tasklet cleaner() {
return new CleanDBTasklet ();
}
@Bean
public Job importUserJob() {
return jobBuilderFactory.get("importUserJob").incrementer(new RunIdIncrementer()).flow(stepClean())
.next(stepImport()).end().listener(new ImportJobExecutionListener(reader())
.validator(new FileNameParameterValidator()).build();
}
@Bean
public Step stepImport() {
return stepBuilderFactory.get("stepImport").<Person, Person>chunk(10).reader(reader()).processor(processor()).writer(writer()).build();
}
@Bean
public Step stepClean() {
return stepBuilderFactory.get("stepClean").tasklet(cleaner()).build();
}
23Copyright © 2017 Capgemini. Tous droits réservés
CSD | Octobre 2017
Exemple d’usage (Deux Jobs par XML 7/8)
<batch:job id="importUserJob">
<batch:step id="stepClean" next="importStep">
<batch:tasklet ref="cleanDBTasklet" />
</batch:step>
<batch:step id="importStep">
<batch:tasklet>
<batch:chunk reader="reader" writer="writer" processor="processor" commit-interval="10" />
</batch:tasklet>
</batch:step>
</batch:job>
<bean id="reader" class="com.capgemini.reader.PersonReaderFromFile" scope="step" />
<bean id="processor" class="com.capgemini.processor.ImportPersonItemProcessor" scope="step" />
<bean id="writer" class="com.capgemini.writer.PersonWriterToDataBase" scope="step" />
<bean id="cleanDBTasklet" class="com.capgemini.tasklet.CleanDBTasklet" />
<batch:job id=“exportUserJob">
<batch:step id=“exportStep">
<batch:tasklet>
<batch:chunk reader="reader" writer="writer" processor="processor" commit-interval="10" />
</batch:tasklet>
</batch:step>
</batch:job>
<bean id="reader" class="com.capgemini.reader.PersonReaderFromDataBase" scope="step" />
<bean id="processor" class="com.capgemini.processor.ExportPersonItemProcessor" scope="step" />
<bean id="writer" class="com.capgemini.writer.PersonWriterToFile" scope="step" />
24Copyright © 2017 Capgemini. Tous droits réservés
CSD | Octobre 2017
Exemple d’usage (L’application enfin 8/8)
La démo
En live …
26Copyright © 2017 Capgemini. Tous droits réservés
CSD | Octobre 2017
La démo (Résultat et Conclusion1/6)
Import de fichier de petite ou moyenne taille :
• Pour les petit fichiers, une moyenne de 4 secondes pour les modes
Synchrone et Asynchrone
• Pour les fichiers de taille moyenne (10.000 lignes), une moyenne de 43
secondes de traitement entre Synchrone et Asynchrone
Import de fichier de grande taille: Une moyenne de traitement de 13
minutes
Export 1000 ligne ou 10.000 lignes: Pour les 1000 ligne, une moyenne de
4 secondes de traitement, et pour les 100.000 ligne, une moyenne de 30
secondes
Export des 200.000 lignes : Une moyenne de traitement de 12 minutes
=> Pour un import et export des 200.000 lignes on dépasse les 10 minutes
27Copyright © 2017 Capgemini. Tous droits réservés
CSD | Octobre 2017
La démo (Solution 2/6)
Pour effectuer l’import et l’export des 200.000 lignes en moins de 10 minutes,
le multi-threading est l’une des solutions
Multi-threading : plusieurs Threads, effectuent une tâche en parallèle
Un nouveau problème : le FileReader et FileWriter ne sont pas des
ThreadSafe
La solution pour le FileReader : splitter le fichier en entrée pour que
chaque ficher soit traité par un Thread
La solution pour le FileWriter: paginer les données de la base de données
pour en exporter plusieurs fichiers et les concaténer à la fin du Process.
28Copyright © 2017 Capgemini. Tous droits réservés
CSD | Octobre 2017
La démo (Le configuration de la solution 3/6)
<batch:job id="transformJob">
<batch:step id="deleteDir" next="cleanDB">
<batch:tasklet ref="fileDeletingTasklet" />
</batch:step>
<batch:step id="cleanDB" next="countThread">
<batch:tasklet ref="cleanDBTasklet" />
</batch:step>
<batch:step id="countThread" next="split">
<batch:tasklet ref="countThreadTasklet" />
</batch:step>
<batch:step id="split" next="partitionerMasterImporter">
<batch:tasklet>
<batch:chunk reader="largeCSVReader" writer="smallCSVWriter"
commit-interval="#{jobExecutionContext['chunk.count']}" />
</batch:tasklet>
</batch:step>
<batch:step id="partitionerMasterImporter" next="partitionerMasterExporter">
<partition step="importChunked" partitioner="filePartitioner">
<handler grid-size="10" task-executor="taskExecutor" />
</partition>
</batch:step>
<batch:step id="partitionerMasterExporter" next="concat">
<partition step="exportChunked" partitioner="dbPartitioner">
<handler grid-size="10" task-executor="taskExecutor" />
</partition>
</batch:step>
<batch:step id="concat">
<batch:tasklet ref="concatFileTasklet" />
</batch:step>
</batch:job>
29Copyright © 2017 Capgemini. Tous droits réservés
CSD | Octobre 2017
La démo (Le configuration 4/6)
<batch:step id="importChunked">
<batch:tasklet>
<batch:chunk reader="smallCSVFileReader" writer="dbWriter"
processor="importProcessor" commit-interval="500">
</batch:chunk>
</batch:tasklet>
</batch:step>
<batch:step id="exportChunked">
<batch:tasklet>
<batch:chunk reader="dbReader" writer="jsonFileWriter" processor="exportProcessor" commit-
interval="#{jobExecutionContext['chunk.count']}">
</batch:chunk>
</batch:tasklet>
</batch:step>
<bean id="jsonFileWriter" class="com.capgemini.writer.PersonWriterToFile" scope="step">
<property name="outputPath" value="csv/chunked/paged-#{stepExecutionContext[page]}.json" />
</bean>
<bean id="dbReader" class="com.capgemini.reader.PersonReaderFromDataBase" scope="step">
<property name="iPersonRepository" ref="IPersonRepository" />
<property name="page" value="#{stepExecutionContext[page]}"/>
<property name="size" value="#{stepExecutionContext[size]}"/>
</bean>
<bean id="countThreadTasklet" class="com.capgemini.tasklet.CountingTasklet" scope="step">
<property name="input" value="file:csv/input/#{jobParameters[filename]}" />
</bean>
<bean id="cleanDBTasklet" class="com.capgemini.tasklet.CleanDBTasklet" />
<bean id="fileDeletingTasklet" class="com.capgemini.tasklet.FileDeletingTasklet">
<property name="directory" value="file:csv/chunked/" />
</bean>
30Copyright © 2017 Capgemini. Tous droits réservés
CSD | Octobre 2017
La démo (Le configuration 5/6)
<bean id="concatFileTasklet" class="com.capgemini.tasklet.FileConcatTasklet">
<property name="directory" value="file:csv/chunked/" />
<property name="outputFilename" value="csv/output/export.json" />
</bean>
<bean id="filePartitioner" class="com.capgemini.partitioner.FilePartitioner">
<property name="outputPath" value="csv/chunked/" />
</bean>
<bean id="dbPartitioner" class="com.capgemini.partitioner.DBPartitioner" scope="step">
<property name="pageSize" value="#{jobExecutionContext['chunk.count']}" />
</bean>
<bean id="largeCSVReader" class="com.capgemini.reader.LineReaderFromFile" scope="step">
<property name="inputPath" value="csv/input/#{jobParameters[filename]}" />
</bean>
<bean id="smallCSVWriter" class="com.capgemini.writer.LineWriterToFile" scope="step">
<property name="outputPath" value="csv/chunked/"></property>
</bean>
<bean id="smallCSVFileReader" class="com.capgemini.reader.PersonReaderFromFile" scope="step">
<constructor-arg value="csv/chunked/#{stepExecutionContext[file]}" />
</bean>
<bean id="importProcessor" class="com.capgemini.processor.ImportPersonItemProcessor" />
<bean id="exportProcessor" class="com.capgemini.processor.ExportPersonItemProcessor" />
<bean id="dbWriter" class="com.capgemini.writer.PersonWriterToDataBase">
<property name="iPersonRepository" ref="IPersonRepository" />
</bean>
31Copyright © 2017 Capgemini. Tous droits réservés
CSD | Octobre 2017
Le test
En multi-threading
32Copyright © 2017 Capgemini. Tous droits réservés
CSD | Octobre 2017
Le Test (Résultat 1/3)
33Copyright © 2017 Capgemini. Tous droits réservés
CSD | Octobre 2017
Le Test (Les Threads 2/3)
Avant le
lancement du Job
Pendant
l’exécution du Job
34Copyright © 2017 Capgemini. Tous droits réservés
CSD | Octobre 2017
Le Test (Output 3/3)
35Copyright © 2017 Capgemini. Tous droits réservés
CSD | Octobre 2017
La Récap
36Copyright © 2017 Capgemini. Tous droits réservés
CSD | Octobre 2017
Récap (Les points + 1/2)
Définit un pattern pour les Batchs
Embarquer les Batchs dans tout type d’application Spring facilement
Fiabilité, maintenabilité
Fonctions avancés par simple configuration tel que le « Multi-Threading »
Intégrée des tests au Batchs
Tolérance aux erreurs et de la reprise suite à une erreur
37Copyright © 2017 Capgemini. Tous droits réservés
CSD | Octobre 2017
Récap (Les points – 2/2)
Le projet Spring Batch Admin n’est plus maintenue : passage obligatoire au
Spring Cloud Data Flow
Difficulté à exécuter un Job définit par annotation dans un projet sous
paquetage JAR embarquant plusieurs Jobs
Des problèmes de compatibilité de version entre Spring Batch et H2
Database , très utile pour tester les Jobs
38Copyright © 2017 Capgemini. Tous droits réservés
CSD | Octobre 2017
Liens utiles
39Copyright © 2017 Capgemini. Tous droits réservés
CSD | Octobre 2017
Liens utiles
Code source complet du projet : https://gitlab.com/mmohamed/spring-batch
Documentations :
• http://projects.spring.io/spring-batch/#quick-start
• https://blog.octo.com/spring-batch-par-quel-bout-le-prendre
• https://blog.netapsys.fr/spring-batch-par-lexemple-2
• http://jeremy-jeanne.developpez.com/tutoriels/spring/spring-batch/
www.capgemini.com
The information contained in this presentation is proprietary.
© 2017 Capgemini. All rights reserved. Rightshore® is a trademark belonging to Capgemini.
About Capgemini
With more than 190,000 people, Capgemini is present in over 40
countries and celebrates its 50th Anniversary year in 2017. A
global leader in consulting, technology and outsourcing services,
the Group reported 2016 global revenues of EUR 12.5 billion.
Together with its clients, Capgemini creates and delivers
business, technology and digital solutions that fit their needs,
enabling them to achieve innovation and competitiveness. A
deeply multicultural organization, Capgemini has developed its
own way of working, Collaborative Business ExperienceTM, and
draws on Rightshore®, its worldwide delivery model
Learn more about us at www.capgemini.com
Rightshore® is a trademark belonging to Capgemini

Spring & SpringBatch FR

  • 1.
    Spring & Batch Octobre2017 M. Mohamed
  • 2.
    2Copyright © 2017Capgemini. Tous droits réservés CSD | Octobre 2017 Plan & Objectifs Plan 1. Un tour au pays de Spring & Spring-Boot 2. C’est quoi un Batch et Spring-Batch ? 3. Comment cela fonctionne ? 4. Notions avancées et applications. 5. Un bon exemple de la vrai vie. Objectifs 1. Assimiler Spring-Batch 2. Détecter les cas d’usages 3. Pouvoir faire du Batch et aller encore plus loin avec…
  • 3.
    Bonjour « SpringFramework »…
  • 4.
    4Copyright © 2017Capgemini. Tous droits réservés CSD | Octobre 2017 Spring Framework (Le Cœur 1/3) Framework Java open-source créé en 2003 par « Pivotal Software » Un conteneur léger (contrairement aux EJBs) S’appui essentiellement sur l’injection de dépendance et l’AOP Intégration facile d’autre Framework (Hibernate , JSF, Thymeleaf ,…)
  • 5.
    5Copyright © 2017Capgemini. Tous droits réservés CSD | Octobre 2017 Spring Framework (Le Boot 2/3) Peu de configuration (auto-configurable tant que c’est possible) Application Runnable , autonome même en production. Embarque même un Tomcat (+ Jetty) , plus besoin du War Plus besoin des fichiers XML (context.xml, web.xml, …) @annotations
  • 6.
    6Copyright © 2017Capgemini. Tous droits réservés CSD | Octobre 2017 Spring Framework (La tendance 3/3 @GoogleTrend)
  • 7.
    C’est quoi un« Batch » ?
  • 8.
    8Copyright © 2017Capgemini. Tous droits réservés CSD | Octobre 2017 Batch (C’est quoi ? 1/2) Traitement de données par lots successifs  Gros volumes de données Plusieurs opérations s'enchainent pour chaque lot Déclenchement automatique ou manuel
  • 9.
    9Copyright © 2017Capgemini. Tous droits réservés CSD | Octobre 2017 Batch (Par l’exemple 2/2) Un exemple concret : import des commandes journalières Lecture d’un lot de commandes depuis un fichier Vérification des commandes Sauvegarde du lot de commandes dans le ST Répéter ce cycle pour chaque lot de commandes jusqu’à la dernière Déclencher par CRON, tous les jours à 5H, avant l’arrivée des collaborateurs
  • 10.
    10Copyright © 2017Capgemini. Tous droits réservés CSD | Octobre 2017 Spring-Batch (C’est quoi encore ? 1/6) Framework open-source pour le Batch Processing Application Batch robuste (Entreprise application) Des fonctions réutilisables pour le traitement des données Ajoute une approche standard pour définir les Jobs Batch
  • 11.
    11Copyright © 2017Capgemini. Tous droits réservés CSD | Octobre 2017 Spring-Batch (En plus 2/6) La gestion des transactions (Commit interval & Rollback) Traitement par lot facilement (Chuncked process) Gestion des erreurs, de la reprise et l’arrêt des Jobs Le tous dans Spring…
  • 12.
    12Copyright © 2017Capgemini. Tous droits réservés CSD | Octobre 2017 Spring-Batch (le concept 3/6) Un Job est défini par un Flow de Step (un ou plusieurs) Un Step définie généralement un Reader, un Processor et Writer Un Step peut définir aussi un simple Tasklet Un référentiel de Job (JobRepository) et un exécuteur de Job (JobLauncher) Source : Spring.io
  • 13.
    13Copyright © 2017Capgemini. Tous droits réservés CSD | Octobre 2017 Spring-Batch (le fonctionnement 4/6) Le Reader lit un élément à la fois Le Processor traite un élément à la fois Quand le lot est lu et traité, le Writer l’écrit Source : Spring.io
  • 14.
    14Copyright © 2017Capgemini. Tous droits réservés CSD | Octobre 2017 Spring-Batch (Notions avancées 5/6) Flow de Step séquentiel, conditionnel ou parallèle Traitement parallèle (Split Flow) et Multi-threading Des Listeners (StepExecutionListener, ChunkListener, ItemReadListener,…) Gestions intégrée des exceptions
  • 15.
    15Copyright © 2017Capgemini. Tous droits réservés CSD | Octobre 2017 Spring-Batch (Diagramme 6/6) Source : Cépria FR
  • 16.
    16Copyright © 2017Capgemini. Tous droits réservés CSD | Octobre 2017 Par l’exemple comme dans la vrai vie …
  • 17.
    17Copyright © 2017Capgemini. Tous droits réservés CSD | Octobre 2017 Exemple d’usage (Contexte 1/8) Application Web pouvant faire appel à des Jobs via l’IHM Suivre le statut des Jobs Permettre de jouer les Jobs en Synchrone et en Asynchrone Trois Jobs, un premier pour importer des fichiers CSV en Base de données, un deuxième pour exporter les données en fichier JSON et un dernier Job pour faire l’import et l’export d’un grand volume de données (200 000 lignes) en moins de 10 minutes
  • 18.
    18Copyright © 2017Capgemini. Tous droits réservés CSD | Octobre 2017 Exemple d’usage (Besoin métier 2/8) Import Job : • Input : un fichier CSV contenant les informations des employées et leurs salaires brutes annuels • Output : les informations transformées et les taxes calculées et enregistrées dans la base de donnés Export Job : • Input : les informations des employées et les taxes calculées et enregistrées dans la base de donnés • Output : un fichier JSON contenant toutes les données. PLUS : une API REST pour effectuer le calcule des taxes et la validation
  • 19.
    19Copyright © 2017Capgemini. Tous droits réservés CSD | Octobre 2017 Exemple d’usage (Architecture & choix techniques 3/8) Utilisation du Spring-Boot avec Spring-MVC et Srping-Batch Intégration du Thymeleaf comme moteur de Templating (+ nekohtml) MySQL Driver, Mokito pour les tests et Jackson pour le support du JSON <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> … <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-batch</artifactId> … <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-jpa</artifactId> … <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-databind</artifactId> … <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-thymeleaf</artifactId> … <groupId>net.sourceforge.nekohtml</groupId> <artifactId>nekohtml</artifactId> … <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId>
  • 20.
    20Copyright © 2017Capgemini. Tous droits réservés CSD | Octobre 2017 Exemple d’usage (Diagramme de la solution 4/8)
  • 21.
    21Copyright © 2017Capgemini. Tous droits réservés CSD | Octobre 2017 Exemple d’usage (Code source 5/8) Une interface est disponible pour définir un Tasklet public interface ItemReader<T> { T read() throws Exception, UnexpectedInputException , ParseException; } public interface ItemWriter<T> { void write(List<? extends T> items) throws Exception; } public interface ItemProcessor<I, O> { O process(I item) throws Exception; } Trois interfaces sont disponibles pour définir un Reader, Processor et Writer public interface Tasklet { RepeatStatus execute(StepContribution contribution, ChunkContext chunkContext) throws Exception } Une interface est disponible pour définir un Partionner public interface Partitioner { Map<String, ExecutionContext> partition(int gridSize); }
  • 22.
    22Copyright © 2017Capgemini. Tous droits réservés CSD | Octobre 2017 Exemple d’usage (Un Job par annotation 6/8) @Bean public ItemReader<Person> reader() { return new PersonReaderFromFile(); } @Bean public ImportPersonItemProcessor processor() { return new ImportPersonItemProcessor(); } @Bean public ItemWriter<Person> writer() { return new PersonWriterToDataBase(); } @Bean public Tasklet cleaner() { return new CleanDBTasklet (); } @Bean public Job importUserJob() { return jobBuilderFactory.get("importUserJob").incrementer(new RunIdIncrementer()).flow(stepClean()) .next(stepImport()).end().listener(new ImportJobExecutionListener(reader()) .validator(new FileNameParameterValidator()).build(); } @Bean public Step stepImport() { return stepBuilderFactory.get("stepImport").<Person, Person>chunk(10).reader(reader()).processor(processor()).writer(writer()).build(); } @Bean public Step stepClean() { return stepBuilderFactory.get("stepClean").tasklet(cleaner()).build(); }
  • 23.
    23Copyright © 2017Capgemini. Tous droits réservés CSD | Octobre 2017 Exemple d’usage (Deux Jobs par XML 7/8) <batch:job id="importUserJob"> <batch:step id="stepClean" next="importStep"> <batch:tasklet ref="cleanDBTasklet" /> </batch:step> <batch:step id="importStep"> <batch:tasklet> <batch:chunk reader="reader" writer="writer" processor="processor" commit-interval="10" /> </batch:tasklet> </batch:step> </batch:job> <bean id="reader" class="com.capgemini.reader.PersonReaderFromFile" scope="step" /> <bean id="processor" class="com.capgemini.processor.ImportPersonItemProcessor" scope="step" /> <bean id="writer" class="com.capgemini.writer.PersonWriterToDataBase" scope="step" /> <bean id="cleanDBTasklet" class="com.capgemini.tasklet.CleanDBTasklet" /> <batch:job id=“exportUserJob"> <batch:step id=“exportStep"> <batch:tasklet> <batch:chunk reader="reader" writer="writer" processor="processor" commit-interval="10" /> </batch:tasklet> </batch:step> </batch:job> <bean id="reader" class="com.capgemini.reader.PersonReaderFromDataBase" scope="step" /> <bean id="processor" class="com.capgemini.processor.ExportPersonItemProcessor" scope="step" /> <bean id="writer" class="com.capgemini.writer.PersonWriterToFile" scope="step" />
  • 24.
    24Copyright © 2017Capgemini. Tous droits réservés CSD | Octobre 2017 Exemple d’usage (L’application enfin 8/8)
  • 25.
  • 26.
    26Copyright © 2017Capgemini. Tous droits réservés CSD | Octobre 2017 La démo (Résultat et Conclusion1/6) Import de fichier de petite ou moyenne taille : • Pour les petit fichiers, une moyenne de 4 secondes pour les modes Synchrone et Asynchrone • Pour les fichiers de taille moyenne (10.000 lignes), une moyenne de 43 secondes de traitement entre Synchrone et Asynchrone Import de fichier de grande taille: Une moyenne de traitement de 13 minutes Export 1000 ligne ou 10.000 lignes: Pour les 1000 ligne, une moyenne de 4 secondes de traitement, et pour les 100.000 ligne, une moyenne de 30 secondes Export des 200.000 lignes : Une moyenne de traitement de 12 minutes => Pour un import et export des 200.000 lignes on dépasse les 10 minutes
  • 27.
    27Copyright © 2017Capgemini. Tous droits réservés CSD | Octobre 2017 La démo (Solution 2/6) Pour effectuer l’import et l’export des 200.000 lignes en moins de 10 minutes, le multi-threading est l’une des solutions Multi-threading : plusieurs Threads, effectuent une tâche en parallèle Un nouveau problème : le FileReader et FileWriter ne sont pas des ThreadSafe La solution pour le FileReader : splitter le fichier en entrée pour que chaque ficher soit traité par un Thread La solution pour le FileWriter: paginer les données de la base de données pour en exporter plusieurs fichiers et les concaténer à la fin du Process.
  • 28.
    28Copyright © 2017Capgemini. Tous droits réservés CSD | Octobre 2017 La démo (Le configuration de la solution 3/6) <batch:job id="transformJob"> <batch:step id="deleteDir" next="cleanDB"> <batch:tasklet ref="fileDeletingTasklet" /> </batch:step> <batch:step id="cleanDB" next="countThread"> <batch:tasklet ref="cleanDBTasklet" /> </batch:step> <batch:step id="countThread" next="split"> <batch:tasklet ref="countThreadTasklet" /> </batch:step> <batch:step id="split" next="partitionerMasterImporter"> <batch:tasklet> <batch:chunk reader="largeCSVReader" writer="smallCSVWriter" commit-interval="#{jobExecutionContext['chunk.count']}" /> </batch:tasklet> </batch:step> <batch:step id="partitionerMasterImporter" next="partitionerMasterExporter"> <partition step="importChunked" partitioner="filePartitioner"> <handler grid-size="10" task-executor="taskExecutor" /> </partition> </batch:step> <batch:step id="partitionerMasterExporter" next="concat"> <partition step="exportChunked" partitioner="dbPartitioner"> <handler grid-size="10" task-executor="taskExecutor" /> </partition> </batch:step> <batch:step id="concat"> <batch:tasklet ref="concatFileTasklet" /> </batch:step> </batch:job>
  • 29.
    29Copyright © 2017Capgemini. Tous droits réservés CSD | Octobre 2017 La démo (Le configuration 4/6) <batch:step id="importChunked"> <batch:tasklet> <batch:chunk reader="smallCSVFileReader" writer="dbWriter" processor="importProcessor" commit-interval="500"> </batch:chunk> </batch:tasklet> </batch:step> <batch:step id="exportChunked"> <batch:tasklet> <batch:chunk reader="dbReader" writer="jsonFileWriter" processor="exportProcessor" commit- interval="#{jobExecutionContext['chunk.count']}"> </batch:chunk> </batch:tasklet> </batch:step> <bean id="jsonFileWriter" class="com.capgemini.writer.PersonWriterToFile" scope="step"> <property name="outputPath" value="csv/chunked/paged-#{stepExecutionContext[page]}.json" /> </bean> <bean id="dbReader" class="com.capgemini.reader.PersonReaderFromDataBase" scope="step"> <property name="iPersonRepository" ref="IPersonRepository" /> <property name="page" value="#{stepExecutionContext[page]}"/> <property name="size" value="#{stepExecutionContext[size]}"/> </bean> <bean id="countThreadTasklet" class="com.capgemini.tasklet.CountingTasklet" scope="step"> <property name="input" value="file:csv/input/#{jobParameters[filename]}" /> </bean> <bean id="cleanDBTasklet" class="com.capgemini.tasklet.CleanDBTasklet" /> <bean id="fileDeletingTasklet" class="com.capgemini.tasklet.FileDeletingTasklet"> <property name="directory" value="file:csv/chunked/" /> </bean>
  • 30.
    30Copyright © 2017Capgemini. Tous droits réservés CSD | Octobre 2017 La démo (Le configuration 5/6) <bean id="concatFileTasklet" class="com.capgemini.tasklet.FileConcatTasklet"> <property name="directory" value="file:csv/chunked/" /> <property name="outputFilename" value="csv/output/export.json" /> </bean> <bean id="filePartitioner" class="com.capgemini.partitioner.FilePartitioner"> <property name="outputPath" value="csv/chunked/" /> </bean> <bean id="dbPartitioner" class="com.capgemini.partitioner.DBPartitioner" scope="step"> <property name="pageSize" value="#{jobExecutionContext['chunk.count']}" /> </bean> <bean id="largeCSVReader" class="com.capgemini.reader.LineReaderFromFile" scope="step"> <property name="inputPath" value="csv/input/#{jobParameters[filename]}" /> </bean> <bean id="smallCSVWriter" class="com.capgemini.writer.LineWriterToFile" scope="step"> <property name="outputPath" value="csv/chunked/"></property> </bean> <bean id="smallCSVFileReader" class="com.capgemini.reader.PersonReaderFromFile" scope="step"> <constructor-arg value="csv/chunked/#{stepExecutionContext[file]}" /> </bean> <bean id="importProcessor" class="com.capgemini.processor.ImportPersonItemProcessor" /> <bean id="exportProcessor" class="com.capgemini.processor.ExportPersonItemProcessor" /> <bean id="dbWriter" class="com.capgemini.writer.PersonWriterToDataBase"> <property name="iPersonRepository" ref="IPersonRepository" /> </bean>
  • 31.
    31Copyright © 2017Capgemini. Tous droits réservés CSD | Octobre 2017 Le test En multi-threading
  • 32.
    32Copyright © 2017Capgemini. Tous droits réservés CSD | Octobre 2017 Le Test (Résultat 1/3)
  • 33.
    33Copyright © 2017Capgemini. Tous droits réservés CSD | Octobre 2017 Le Test (Les Threads 2/3) Avant le lancement du Job Pendant l’exécution du Job
  • 34.
    34Copyright © 2017Capgemini. Tous droits réservés CSD | Octobre 2017 Le Test (Output 3/3)
  • 35.
    35Copyright © 2017Capgemini. Tous droits réservés CSD | Octobre 2017 La Récap
  • 36.
    36Copyright © 2017Capgemini. Tous droits réservés CSD | Octobre 2017 Récap (Les points + 1/2) Définit un pattern pour les Batchs Embarquer les Batchs dans tout type d’application Spring facilement Fiabilité, maintenabilité Fonctions avancés par simple configuration tel que le « Multi-Threading » Intégrée des tests au Batchs Tolérance aux erreurs et de la reprise suite à une erreur
  • 37.
    37Copyright © 2017Capgemini. Tous droits réservés CSD | Octobre 2017 Récap (Les points – 2/2) Le projet Spring Batch Admin n’est plus maintenue : passage obligatoire au Spring Cloud Data Flow Difficulté à exécuter un Job définit par annotation dans un projet sous paquetage JAR embarquant plusieurs Jobs Des problèmes de compatibilité de version entre Spring Batch et H2 Database , très utile pour tester les Jobs
  • 38.
    38Copyright © 2017Capgemini. Tous droits réservés CSD | Octobre 2017 Liens utiles
  • 39.
    39Copyright © 2017Capgemini. Tous droits réservés CSD | Octobre 2017 Liens utiles Code source complet du projet : https://gitlab.com/mmohamed/spring-batch Documentations : • http://projects.spring.io/spring-batch/#quick-start • https://blog.octo.com/spring-batch-par-quel-bout-le-prendre • https://blog.netapsys.fr/spring-batch-par-lexemple-2 • http://jeremy-jeanne.developpez.com/tutoriels/spring/spring-batch/
  • 40.
    www.capgemini.com The information containedin this presentation is proprietary. © 2017 Capgemini. All rights reserved. Rightshore® is a trademark belonging to Capgemini. About Capgemini With more than 190,000 people, Capgemini is present in over 40 countries and celebrates its 50th Anniversary year in 2017. A global leader in consulting, technology and outsourcing services, the Group reported 2016 global revenues of EUR 12.5 billion. Together with its clients, Capgemini creates and delivers business, technology and digital solutions that fit their needs, enabling them to achieve innovation and competitiveness. A deeply multicultural organization, Capgemini has developed its own way of working, Collaborative Business ExperienceTM, and draws on Rightshore®, its worldwide delivery model Learn more about us at www.capgemini.com Rightshore® is a trademark belonging to Capgemini

Notes de l'éditeur

  • #5 Les classes n’ont pas besoin d’implémenter une quelconque interface pour être prises en charge par le framework (au contraire des serveur d'applications J2EE et des EJBs). La programmation orientée aspect, ou POA est un paradigme de programmation qui permet de traiter séparément les préoccupations transversales, qui relèvent souvent de la technique, des préoccupations métier, qui constituent le cœur d'une application
  • #6 Mode Auto-configuration basé sur les annotations Fonctionne sans fichier XML
  • #9 Déclenché par CRON ou par commande Bash
  • #10 Importation des commandes de la veille du Front (Boutique en ligne) vers le SI de traitement des commandes clients Intégrer les commandes avant le début du service
  • #13 Un JobInstance = un Job + JobParameters Un JobExecution = JobInstance + Execution
  • #14 - Le commit-interval est au niveau du Writer
  • #15 - Flow conditionnel : <job id="job"> <step id="stepA"> <next on="FAILED" to="stepB" /> <next on="*" to="stepC" /> </step> <step id="stepB" next="stepC" /> <step id="stepC" /> </job> -Split Flow : <step id="stepA" next="stepB"/> <split id="stepB" next="stepC"> <flow> <step id="stepB11" next="stepB12"/> <step id="stepB12"/> </flow> <flow> <step id="stepB21"/> </flow> </split> <step id="stepC"/>
  • #16 Run Tier : a pour mission la planification et le lancement des Jobs (produits tiers généralement) Job Tier : responsable de l‘exécution globale du Job Application Tier : contient les composants requis pour exécuter le Job Data Tier : fournit l'intégration avec les sources de données physiques pouvant inclure bases de données, fichiers ou files d'attente