Spring Batch
Achref El Mouelhi
Docteur de l’université d’Aix-Marseille
Chercheur en programmation par contrainte (IA)
Ingénieur en génie logiciel
[Link]@[Link]
H & H: Research and Training 1 / 32
Plan
1 Introduction
2 Exemple avec un Job et un Step
3 Exemple avec un Job, un Tasklet et un Step
H & H: Research and Training 2 / 32
Introduction
Spring Batch
Spring Batch
H I ©
Framework open-source (unique) pour le traitement par lots
U
Fournissant des fonctions réutilisables pour L grands volumes
Edes
de données
L MO
r e
Fonctionnement principalf E= { lecture de données ⇒ traitement de
données ⇒ A ch de données }
écriture
©
Configurable par XML ou classes Java
H & H: Research and Training 3 / 32
Introduction
Spring Batch
Exemple réel : opération de pointage
Les employés d’une entreprise pointent en début et fin de journée
H I ©
EL
La pointeuse renvoie généralement un fichier texte (d’extension
.csv)
M OU
f E L les pointages doubles, corriger
Il faut lire les données, supprimer
le format de dateh e
c etrtout sauvegarder dans la base de données
Traitement
A
© périodique et répétitif
Pour automatiser le lancement, on peut utiliser Spring Batch
H & H: Research and Training 4 / 32
Introduction
Spring Batch
H I ©
U EL
O
f E LM
ch r e
©A
Source : documentation officielle
H & H: Research and Training 5 / 32
Introduction
Spring Batch
Explication
Job = { Step } (conteneur de Step).
Step = ItemReader + ItemProcessor + ItemWriter.
H I ©
Chunk indique le nombre d’item à chargerE
U en Lmémoire. Par
exemple : si on passe la valeur 4 à O
d’L
M chunk, on lit les items un par
un, une fois que le nombre
e f E éléments lus est égal à 4, le bloc
entier est traité par rItemProcessor
c h puis écrit par ItemWriter,
© A avec les autres de la même manière.
et on continue
JobLauncher exécute les jobs.
JobRepository contient les méta-données relatives aux différents
traitements.
H & H: Research and Training 6 / 32
Introduction
Spring Batch
Exemple avec chunk(2)
H I ©
U EL
O
f E LM
ch r e
©A
Source : documentation officielle
H & H: Research and Training 7 / 32
Introduction
Spring Batch
Création de projet Spring Boot
Aller dans File > New > Other
Chercher Spring, dans Spring Boot sélectionner Spring Starter Project et cli-
quer sur Next >
H I ©
EL
Saisir
OU
first-spring-batch dans Name,
M
E L
[Link] dans Group,
f
c e
hr dans Artifact
firstspringbatch
© A
[Link] dans Package
Cliquer sur Next
Chercher et cocher les cases correspondantes aux Spring Data JPA, MySQL Driver,
Spring Web, Spring Boot DevTools, Lombok et Spring Batch
Cliquer sur Next puis sur Finish
H & H: Research and Training 8 / 32
Introduction
Spring Batch
Explication
Le package contenant le point d’entrée de notre application (la classe
contenant le puclic static void main) est [Link]
I ©
Tous les autres packages dao, model... doivent être dans le package
H
demo.
UEL
O
f E LM
ch r e
©A
H & H: Research and Training 9 / 32
Introduction
Spring Batch
Explication
Le package contenant le point d’entrée de notre application (la classe
contenant le puclic static void main) est [Link]
I ©
Tous les autres packages dao, model... doivent être dans le package
H
demo.
U EL
O
f
Pour la suite, nous considérons E LM
r e
ch à définir dans [Link]
A
une entité Personne
©
une interface DAO PersonneRepository à définir dans
[Link]
un contrôleur REST PersonneController à définir dans
[Link]
H & H: Research and Training 9 / 32
Introduction
Spring Batch
Créons une entité Personne dans [Link]
@NoArgsConstructor
@AllArgsConstructor
@Data
H I ©
@Entity
UEL
public class Personne {
O
@Id
f E LM
private Long num;
ch r e
@GeneratedValue(strategy = [Link])
©A
private String nom;
private String prenom;
private Long salaire;
}
H & H: Research and Training 10 / 32
Introduction
Spring Batch
Préparons notre interface DAO PersonneRepository
package [Link];
import [Link]. H I ©
EL
OU
JpaRepository;
L M
f E
import [Link];
r e
A chPersonneRepository
©
public interface
JpaRepository<Personne, Long> {
extends
H & H: Research and Training 11 / 32
Introduction
Spring Batch
Considérons le fichier [Link] à créer dans
src/main/resources
H I ©
nom_p,prenom_p,salaire_p
UEL
O
wick,john,1700
dalton,jack,2000
f E LM
maggio,carol,1900
ch r e
hoffman,mike,2300
©A
H & H: Research and Training 12 / 32
Exemple avec un Job et un Step
Spring Batch
Contexte et objectif
H I ©
La RH de notre entreprise nous fournit régulièrement un fichier
EL
.csv contenant les noms et prénoms des nouvelles recrues ainsi
que les salaires négociés.
M OU
À partir de ce fichier, nousE
f L
souhaitons ajouter ces personnes dans
chr
la base de données. e
© A
Nous souhaitons aussi que le nom et la première lettre du prénom
soient écrits en majuscule.
H & H: Research and Training 13 / 32
Exemple avec un Job et un Step
Dans [Link], ajoutons les données permettant la connexion à la
base de données et la configuration de Hibernate
[Link] = jdbc:mysql://localhost:3306/batch?
serverTimezone=UTC
[Link] = root
[Link] = root
[Link]-auto = update
[Link]-sql = true
[Link] = [Link].
H I ©
EL
MySQL8Dialect
[Link]
O U
[Link]-strategy = [Link].
f E LM
ch r e
©A
H & H: Research and Training 14 / 32
Exemple avec un Job et un Step
Dans [Link], ajoutons les données permettant la connexion à la
base de données et la configuration de Hibernate
[Link] = jdbc:mysql://localhost:3306/batch?
serverTimezone=UTC
[Link] = root
[Link] = root
[Link]-auto = update
[Link]-sql = true
[Link] = [Link].
H I ©
EL
MySQL8Dialect
[Link]
O U
[Link]-strategy = [Link].
f E LM
r e
Indiquons également l’emplacement de notre fichier CSV
ch
©A
inputFile=classpath:/[Link]
H & H: Research and Training 14 / 32
Exemple avec un Job et un Step
Dans [Link], ajoutons les données permettant la connexion à la
base de données et la configuration de Hibernate
[Link] = jdbc:mysql://localhost:3306/batch?
serverTimezone=UTC
[Link] = root
[Link] = root
[Link]-auto = update
[Link]-sql = true
[Link] = [Link].
H I ©
EL
MySQL8Dialect
[Link]
O U
[Link]-strategy = [Link].
f E LM
r e
Indiquons également l’emplacement de notre fichier CSV
ch
©A
inputFile=classpath:/[Link]
Demandons à Spring Boot de ne pas lancer les jobs au démarrage de l’application
[Link] = false
H & H: Research and Training 14 / 32
Exemple avec un Job et un Step
Dans [Link], ajoutons les données permettant la connexion à la
base de données et la configuration de Hibernate
[Link] = jdbc:mysql://localhost:3306/batch?
serverTimezone=UTC
[Link] = root
[Link] = root
[Link]-auto = update
[Link]-sql = true
[Link] = [Link].
H I ©
EL
MySQL8Dialect
[Link]
O U
[Link]-strategy = [Link].
f E LM
r e
Indiquons également l’emplacement de notre fichier CSV
ch
©A
inputFile=classpath:/[Link]
Demandons à Spring Boot de ne pas lancer les jobs au démarrage de l’application
[Link] = false
Autorisons Spring Batch à générer ses tables nécessaires pour la gestion de lots
[Link]-schema=always
H & H: Research and Training 14 / 32
Exemple avec un Job et un Step
Spring Batch
Créons une classe de configuration pour Spring Batch
package [Link];
import [Link].
H I ©
[Link];
UEL
O
LM
import [Link].
Configuration;
r e f E
@Configuration
ch
©A
@EnableBatchProcessing
public class SpringBatchConfig {
H & H: Research and Training 15 / 32
Exemple avec un Job et un Step
Spring Batch
Dans la classe SpringBatchConfig, nous commençons par injecter les 5 éléments
indispensable pour le lancement d’un job
@Configuration
@EnableBatchProcessing
public class SpringBatchConfig {
@Autowired private JobBuilderFactory jobBuilderFactory;
@Autowired private StepBuilderFactory stepBuilderFactory;
H I ©
@Autowired private ItemReader<Personne> itemReader;
UEL
@Autowired private ItemWriter<Personne> itemWriter;
O
LM
@Autowired private ItemProcessor<Personne, Personne> itemProcessor;
}
r e f E
ch
©A
H & H: Research and Training 16 / 32
Exemple avec un Job et un Step
Spring Batch
Dans la classe SpringBatchConfig, nous commençons par injecter les 5 éléments
indispensable pour le lancement d’un job
@Configuration
@EnableBatchProcessing
public class SpringBatchConfig {
@Autowired private JobBuilderFactory jobBuilderFactory;
@Autowired private StepBuilderFactory stepBuilderFactory;
H I ©
@Autowired private ItemReader<Personne> itemReader;
UEL
@Autowired private ItemWriter<Personne> itemWriter;
O
LM
@Autowired private ItemProcessor<Personne, Personne> itemProcessor;
}
r e f E
ch
©A
Les imports nécessaires
import [Link].
JobBuilderFactory;
import [Link].
StepBuilderFactory;
import [Link];
import [Link];
import [Link];
H & H: Research and Training 16 / 32
Exemple avec un Job et un Step
Spring Batch
Définissons un Bean pour le Job (dans SpringBatchConfig)
@Bean
public Job job(Step step1) {
return [Link]("Recrutement") // le nom de notre job
.start(step1)
}
.build();
H I ©
UEL
O
f E LM
ch r e
©A
H & H: Research and Training 17 / 32
Exemple avec un Job et un Step
Spring Batch
Définissons un Bean pour le Job (dans SpringBatchConfig)
@Bean
public Job job(Step step1) {
return [Link]("Recrutement") // le nom de notre job
.start(step1)
}
.build();
H I ©
UEL
O
f E LM
Nous devons donner à Spring plus de détail sur le Step
@Bean
ch r e
©A
public Step step1() {
return [Link]("première étape: chargement de fichier"
)
.<Personne, Personne>chunk(2)
.reader(itemReader)
.processor(itemProcessor)
.writer(itemWriter)
.build();
}
H & H: Research and Training 17 / 32
Exemple avec un Job et un Step
Définissons un Bean pour la lecture de données (dans SpringBatchConfig)
@Bean
public FlatFileItemReader<Personne> reader(@Value("${inputFile}")
Resource resource) {
return new FlatFileItemReaderBuilder<Personne>()
.name("personItemReader")
.resource(resource)
.linesToSkip(1)
.delimited()
H I ©
EL
.names(new String[]{"nom", "prenom", "salaire"})
setTargetType([Link]);
O U
.fieldSetMapper(new BeanWrapperFieldSetMapper<Personne>() {{
}})
.build();
f E LM
}
ch r e
©A
H & H: Research and Training 18 / 32
Exemple avec un Job et un Step
Définissons un Bean pour la lecture de données (dans SpringBatchConfig)
@Bean
public FlatFileItemReader<Personne> reader(@Value("${inputFile}")
Resource resource) {
return new FlatFileItemReaderBuilder<Personne>()
.name("personItemReader")
.resource(resource)
.linesToSkip(1)
.delimited()
H I ©
EL
.names(new String[]{"nom", "prenom", "salaire"})
setTargetType([Link]);
O U
.fieldSetMapper(new BeanWrapperFieldSetMapper<Personne>() {{
}})
.build();
f E LM
}
ch r e
©A
Les imports nécessaires
import [Link];
import [Link].
FlatFileItemReaderBuilder;
import [Link];
import [Link];
H & H: Research and Training 18 / 32
Exemple avec un Job et un Step
Spring Batch
Explication
@Value("${inputFile}") Resource resource : permet de
récupérer le nom de fichier défini dans [Link] et
l’injecter dans resource
H I ©
UEL
O
linesToSkip(1) : pour ignorer la première ligne (contenant l’entête)
de notre fichier CSV
f E LM
ch r e
delimeted() : pour construire un objet DelimitedLineTokenizer
©A
names() : pour spécifier les noms des attributs de la classe Personne
présents dans le fichier
fieldSetMapper() : pour spécifier le type de mapping (ici le type de
sortie est un objet de la classe Personne)
H & H: Research and Training 19 / 32
Exemple avec un Job et un Step
Définissons un Component appelé PersonneItemProcessor pour spécifier ce qu’on fera
avec l’objet lu
package [Link];
import [Link];
import [Link];
import [Link];
@Component
H I ©
EL
public class PersonneItemProcessor implements ItemProcessor<Personne,
Personne> {
O U
@Override
f E LM
Exception {
ch r e
public Personne process(final Personne personne) throws
©A
var nom = [Link]().toUpperCase();
[Link](nom);
var prenom = [Link]();
prenom = [Link](0, 1).toUpperCase() + prenom.
substring(1).toLowerCase();
[Link](prenom);
return personne;
}
}
H & H: Research and Training 20 / 32
Exemple avec un Job et un Step
Définissons un Component appelé PersonneItemWriter pour écrire l’objet transformé
package [Link];
import [Link];
import [Link];
import [Link];
import [Link];
H I ©
EL
import [Link];
import [Link];
O U
@Component
f E LM
@Autowired
ch r e
public class PersonneItemWriter implements ItemWriter<Personne> {
©A
private PersonneRepository personneRepository;
@Override
public void write(List<? extends Personne> items) throws
Exception {
[Link](items);
[Link](items);
}
}
H & H: Research and Training 21 / 32
Exemple avec un Job et un Step
Spring Batch
Créons un contrôleur (qui nous permettra de lancer le Job) et commençons par injecter le
Job et JobLauncher
package [Link];
import [Link];
import [Link];
H I ©
EL
import [Link];
import [Link];
import
O U
[Link];
import
LM
[Link];
f E
@RestController
ch r e
©A
public class JobInvokerController {
@Autowired
private JobLauncher jobLauncher;
@Autowired
private Job processJob;
H & H: Research and Training 22 / 32
Exemple avec un Job et un Step
Ajoutons l’action qui permettra de lancer le Job
package [Link];
@RestController
public class JobInvokerController {
@Autowired
private JobLauncher jobLauncher;
H I ©
@Autowired
U EL
private Job processJob;
O
@RequestMapping("/loadData")
f E LM
r e
public String handle() throws Exception {
ch
©A
JobParameters jobParameters = new JobParametersBuilder()
.addLong("time", [Link]())
.toJobParameters();
[Link](processJob, jobParameters);
return "Le job a été exécuté";
}
}
H & H: Research and Training 23 / 32
Exemple avec un Job, un Tasklet et un Step
Spring Batch
Objectif
H I ©
U
Supprimer le fichier [Link] après ajout L la base de
Edans
données
L MO
Utiliser un Tasklet e
r f
apr Ele premier Step pour supprimer le
ès
fichier A ch
©
H & H: Research and Training 24 / 32
Exemple avec un Job, un Tasklet et un Step
Spring Batch
Tasklet
Comme un Step
H I ©
sans ItemWriter
UEL
O
généralement sans valeur de retour
f E LM
Utilisé souvent pour
ch r e
©A
appeler une procédure stockée
exécuter un script
H & H: Research and Training 25 / 32
Exemple avec un Job, un Tasklet et un Step
Spring Batch
Dans la classe SpringBatchConfig, ajoutons la déclaration de notre Tasklet
@Configuration
@EnableBatchProcessing
public class SpringBatchConfig {
@Autowired private JobBuilderFactory jobBuilderFactory;
H I ©
EL
@Autowired private StepBuilderFactory stepBuilderFactory;
@Autowired private ItemReader<Personne> itemReader;
@Autowired private ItemWriter<Personne> itemWriter;
O U
f
@Autowired private Tasklet tasklet;
E LM
@Autowired private ItemProcessor<Personne, Personne> itemProcessor;
ch r e
©A
// ...
H & H: Research and Training 26 / 32
Exemple avec un Job, un Tasklet et un Step
Spring Batch
Dans la classe SpringBatchConfig, ajoutons la déclaration de notre Tasklet
@Configuration
@EnableBatchProcessing
public class SpringBatchConfig {
@Autowired private JobBuilderFactory jobBuilderFactory;
H I ©
EL
@Autowired private StepBuilderFactory stepBuilderFactory;
@Autowired private ItemReader<Personne> itemReader;
@Autowired private ItemWriter<Personne> itemWriter;
O U
f
@Autowired private Tasklet tasklet;
E LM
@Autowired private ItemProcessor<Personne, Personne> itemProcessor;
ch r e
©A
// ...
L’import nécessaire
import [Link];
H & H: Research and Training 26 / 32
Exemple avec un Job, un Tasklet et un Step
Spring Batch
Modifions le Job précédent pour lancer le Tasklet après step1
@Bean
public Job job(@Qualifier("step1") Step step1, @Qualifier("deleteFile")
Step deleteFile) {
return [Link]("Recrutement")
.start(step1)
H I ©
EL
.next(deleteFile)
}
.build();
O U
f E LM
ch r e
©A
H & H: Research and Training 27 / 32
Exemple avec un Job, un Tasklet et un Step
Spring Batch
Modifions le Job précédent pour lancer le Tasklet après step1
@Bean
public Job job(@Qualifier("step1") Step step1, @Qualifier("deleteFile")
Step deleteFile) {
return [Link]("Recrutement")
.start(step1)
H I ©
EL
.next(deleteFile)
}
.build();
O U
f E LM
ch r e
Définissons le Tasklet défini dans le Job
@Bean ©A
public Step deleteFile() {
return [Link]("deuxième étape : suppression
du fichier CSV")
.tasklet(tasklet)
.build();
}
H & H: Research and Training 27 / 32
Exemple avec un Job, un Tasklet et un Step
Définissons un Component appelé FileDeletingTasklet pour la suppression de notre fichier CSV
package [Link];
import [Link];
import [Link];
import [Link];
import [Link];
import [Link];
import [Link];
import
import
[Link];
[Link];
H I ©
EL
import [Link];
@Component
O U
LM
public class FileDeletingTasklet implements Tasklet {
@Value("${inputFile}")
r e
private Resource resource;
f E
ch
©A
public RepeatStatus execute(StepContribution contribution, ChunkContext chunkContext)
throws Exception {
File file = [Link]();
boolean deleted = [Link]();
if (!deleted) {
throw new UnexpectedJobExecutionException("Impossible de supprimer le
fichier " + [Link]());
}
[Link]("Fichier supprimé : " + [Link]());
return [Link];
}
}
H & H: Research and Training 28 / 32
Exemple avec un Job, un Tasklet et un Step
Spring Batch
Rien à changer dans le contrôleur précédent
@RestController
public class JobInvokerController {
@Autowired
private JobLauncher jobLauncher;
H I ©
@Autowired
U EL
private Job processJob;
O
@RequestMapping("/loadData")
f E LM
r e
public String handle() throws Exception {
ch
©A
JobParameters jobParameters = new JobParametersBuilder()
.addLong("time", [Link]())
.toJobParameters();
[Link](processJob, jobParameters);
return "Le job a été exécuté";
}
}
H & H: Research and Training 29 / 32
Exemple avec un Job, un Tasklet et un Step
Spring Batch
Lancez le projet et allez à localhost:8080/loadData et vérifiez la présence des
messages suivants
....
H I ©
EL
Executing step: [deuxième étape : suppression du fichier CSV]
U
O
Fichier supprimé : C:\Users\elmou\eclipse-workspace\first-spring-batch\
LM
target\classes\[Link]
r e E
Step: [deuxième étape : suppression du fichier CSV] executed in 368ms
f
Job: [SimpleJob: [name=Recrutement]] completed with the following
ch
parameters: [{time=1600800074441}] and the following status: [
©A
COMPLETED] in 2s114ms
....
H & H: Research and Training 30 / 32
Exemple avec un Job, un Tasklet et un Step
Spring Batch
Explication
Un message nous indique que le fichier [Link] a été
supprimé
Ce n’est pas le [Link] qu’on a créé dans
H I ©
src/main/resources
UEL
O
f E LM
Le chemin affiché indique que le fichier supprimé se trouvait dans
ch r e
first-spring-batch/target/classes
©A
En effet, Spring a déplacé [Link] qu’on a créé dans
src/main/resources dans target/classes/
Faites un clic droit sur le projet et cliquez sur Refresh et allez
vérifiez que Spring a de nouveau déplacé [Link] dans
first-spring-batch/target/classes
H & H: Research and Training 31 / 32
Exemple avec un Job, un Tasklet et un Step
Spring Batch
Question
Pourquoi Spring Boot a t-il redémarré l’application après suppression
de fichier ? H I ©
UEL
O
f E LM
ch r e
©A
H & H: Research and Training 32 / 32
Exemple avec un Job, un Tasklet et un Step
Spring Batch
Question
Pourquoi Spring Boot a t-il redémarré l’application après suppression
de fichier ? H I ©
UEL
O
f E LM
Réponse
ch r e
©A
Devtools a détecté un changement (suppression de fichier) et par
conséquence a redémarré l’application.
H & H: Research and Training 32 / 32