Cet article fait suite aux précédents posts sur TDD et BDD avec Spring Batch.

Le but est de packager et exécuter directement un batch Spring Batch sans ajout de configuration spécifique de packaging ni d’installation préalable d’environnement d’exécution particulier.

Le projet Github springbatch-sample montre comment Spring Boot permet de construire de manière simple un livrable auto exécutable.

La documentation de référence spring détaille les étapes pour un projet avec une seule datasource contenant un seul job et sans paramètres de lancement.

On va voir dans l’article les configurations Spring Boot nécessaires pour lancer un job d’alimentation de données dans une base, avec datasources technique et fonctionnelle séparées et comment traiter les paramètres d’entrée et propriétés système.

Configuration maven

Déclaration projet parent Spring Boot


<parent>
   <groupId>org.springframework.boot</groupId>
   <artifactId>spring-boot-starter-parent</artifactId>
   <version>1.2.2.RELEASE</version>
</parent>

Ajout dépendance maven Spring Boot pour les batchs (plus besoin de déclarer les dépendances spring)


<dependency>
   <groupId>org.springframework.boot</groupId>
   <artifactId>spring-boot-starter-batch</artifactId>
</dependency>

Ajout du plugin spring boot

 

<plugin>
   <groupId>org.springframework.boot</groupId>
   <artifactId>spring-boot-maven-plugin</artifactId>
</plugin>

Configuration java du runner

package com.giovanetti.sample.batch.job;
import com.giovanetti.support.batch.annotations.TechnicalDataSource;
import com.giovanetti.support.batch.function.Consumer;
import com.giovanetti.support.batch.function.Function;
import org.springframework.batch.core.explore.JobExplorer;
import org.springframework.batch.core.explore.support.JobExplorerFactoryBean;
import org.springframework.batch.core.launch.JobLauncher;
import org.springframework.beans.factory.FactoryBean;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.batch.BatchAutoConfiguration;
import org.springframework.boot.autoconfigure.batch.JobLauncherCommandLineRunner;
import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
import org.springframework.boot.autoconfigure.jdbc.DataSourceTransactionManagerAutoConfiguration;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import javax.sql.DataSource;
@Configuration
@EnableAutoConfiguration(exclude={DataSourceTransactionManagerAutoConfiguration.class, BatchAutoConfiguration.class, DataSourceAutoConfiguration.class})
@SpringBootApplication
public class BatchApplication {
@Bean
public JobExplorer jobExplorer(@TechnicalDataSource DataSource dataSource) {
JobExplorerFactoryBean factory = new JobExplorerFactoryBean();
factory.setDataSource(dataSource);
Consumer.acceptWithRawException(factory, JobExplorerFactoryBean::afterPropertiesSet);
return Function.applyWithRawException(factory, FactoryBean::getObject);
}
@Bean
public JobLauncherCommandLineRunner jobLauncherCommandLineRunner(JobLauncher jobLauncher, JobExplorer jobExplorer, @Value(
"${job.name}") String jobName) {
JobLauncherCommandLineRunner runner = new JobLauncherCommandLineRunner(jobLauncher, jobExplorer);
runner.setJobNames(jobName);
return runner;
}
public static void main(String[] args) {
System.exit(SpringApplication.exit(SpringApplication.run(BatchApplication.class, args)));
}
}

L’écriture de la configuration des beans JobExplorer et JobLauncherCommandLineRunner n’est pas nécessaire dans le cas de projets mono job et mono datasource.

Test du runner à vide

package com.giovanetti.sample.batch.job;
import com.giovanetti.support.batch.configuration.GenericTestConfiguration;
import com.giovanetti.support.batch.rule.BatchProperties;
import org.junit.Before;
import org.junit.ClassRule;
import org.junit.Rule;
import org.junit.Test;
import org.junit.contrib.java.lang.system.ExpectedSystemExit;
import org.junit.contrib.java.lang.system.ProvideSystemProperty;
import org.junit.rules.TemporaryFolder;
import org.springframework.batch.core.launch.support.ExitCodeMapper;
import java.io.IOException;
public class BatchApplicationAlimentationIT {
private final static String FUNCTIONAL_SCRIPT = "schema-functional.sql";
@ClassRule
public final static BatchProperties batchProperties = BatchProperties.getDefault();
@ClassRule
public static ProvideSystemProperty systemProperty = new ProvideSystemProperty("job.name", JobAlimentationConfiguration.JOB_NAME);
@Rule
public TemporaryFolder temporaryFolder = new TemporaryFolder();
/**
* @see <a href="http://www.stefan-birkner.de/system-rules/index.html">System Rules</a>
*/
@Rule
public final ExpectedSystemExit exit = ExpectedSystemExit.none();
@Before
public void before() {
GenericTestConfiguration.buildFunctionalDataSource(FUNCTIONAL_SCRIPT);
GenericTestConfiguration.buildTechnicalDataSource();
}
@Test
public void run() throws IOException {
exit.expectSystemExitWithStatus(ExitCodeMapper.JVM_EXITCODE_COMPLETED);
BatchApplication.main(
new String[]{JobAlimentationConfiguration.INPUT_FILE_PARAMETER + "=" + temporaryFolder.newFile()
.getPath()});
}
@Test(expected = IllegalStateException.class)
public void run_SiParametreInvalide_AlorsExitWithError() {
BatchApplication.main(new String[]{});
}
}

La librairie system rule permet de gérer de manière simple et fiable les propriétés système et les codes de sortie.

Packager le livrable jar exécutable

maven clean package

Pré-requis d’environnement pour exécuter le job d’alimentation

  • Une datasource technique
  • Une datasource fonctionnelle
  • Un fichier de données csv
  • Un fichier de propriétés contenant les clés
    • ds.technical.driverclassname
    • ds.technical.url
    • ds.technical.username
    • ds.technical.password
    • ds.functional.driverclassname
    • ds.functional.url
    • ds.functional.username
    • ds.functional.password
    • commit.interval

Exécuter le jar

avec maven

mvn spring-boot:run -Drun.arguments=input.file.path=alimentation.csv

plus les propriétés de VM -Dbatch.properties.path=file:batch.properties -Djob.name=alimentationJob

ou bien directement le jar

java -Dbatch.properties.path=file:batch.properties -Djob.name=alimentationJob -jar springbatch-sample.jar input.file.path=alimentation.csv

Voir la documentation de référence spring pour les détails des jar exécutable Spring Boot.