Spring Batch je open source framework pro dávkové zpracování (batch processing). Dávkové zpracování znamená vykonání série programů bez účasti uživatele. Většinou se jedná o akce, které se vykonávají pravidelně v určitý čas jako například vygenerování statistik ke konci měsíce, zjištění změn za poslední týden (např. nové příspěvky za toto období), zpracování výkazů ke konci dne, týdne, měsíce, …
Základní pojmy ve Spring Batch
- JobLauncher: Vstupní místo, kde se spouští job.
- Job: Definuje co se má provést (definuje dávku). Každý job může obsahovat několik kroků (Step).
- Step: Část jobu, jeden z kroků při provádění (jeden z kroků dávky). Step obsahuje atribut next, který udává, jaký další step se má vykonat po tom aktuálním. Step obsahuje Tasklet.
- Tasklet: Je částí kroku a definuje, co se má provést (reference na třídu implementující rozhraní
org.springframework.batch.core.step.tasklet.Tasklet
) a nebo může ještě obsahovat Chunk.
- Chunk: Nejmenší část, ve které se určuje co se má načíst (Reader), jak to zpracovat (Processor) a co má být výstupem (Writer).
Jak vypadá typický job
- načtení dat (z databáze, ze souboru, …)
- zpracování dat (výpočty, validace, filtrování, …)
- zápis dat (do databáze, do různých typů souborů – pdf, doc, txt, …)
Jednoduchý projekt
V následujícím jednoduchém projektu vytvoříme a spustíme job, který bude obsahovat jediný Step (a ten jediný Tasklet), který pouze vypíše text.
Zde je struktura projektu. Jedná se Maven projekt.
│ pom.xml
│
└───src
├───main
│ └───java
│ └───cz
│ └───vitfo
│ ExecuteJob.java
│ MyTasklet.java
│
└───resources
context.xml
pom.xml
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>cz.vito</groupId>
<artifactId>springbatch</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>jar</packaging>
<name>springbatch</name>
<url>http://maven.apache.org</url>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<spring.framework.version>3.2.1.RELEASE</spring.framework.version>
<spring.batch.version>3.0.2.RELEASE</spring.batch.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.batch</groupId>
<artifactId>spring-batch-core</artifactId>
<version>${spring.batch.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.batch</groupId>
<artifactId>spring-batch-infrastructure</artifactId>
<version>${spring.batch.version}</version>
</dependency>
</dependencies>
</project>
Do pom.xml stačí přidat pouze dvě závislosti a to na org.springframework.batch
a spring-batch-infrastructure
.
context.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans:beans xmlns="http://www.springframework.org/schema/batch"
xmlns:beans="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/batch
http://www.springframework.org/schema/batch/spring-batch-3.0.xsd">
<!-- Beans definition -->
<beans:bean id="jobRepository" class="org.springframework.batch.core.repository.support.MapJobRepositoryFactoryBean">
<beans:property name="transactionManager" ref="transactionManager" />
</beans:bean>
<beans:bean id="jobLauncher" class="org.springframework.batch.core.launch.support.SimpleJobLauncher">
<beans:property name="jobRepository" ref="jobRepository" />
</beans:bean>
<beans:bean id="transactionManager" class="org.springframework.batch.support.transaction.ResourcelessTransactionManager" />
<beans:bean id="myTasklet" class=" cz.vitfo.MyTasklet" />
<!-- Job definition -->
<job id="myJob">
<step id="myStep">
<tasklet ref="myTasklet"></tasklet>
</step>
</job>
</beans:beans>
Job launcher potřebuje mít definovánu job repository, do které si ukládá údaje o jobech. Job repository potřebuje mít definován transaction manager. Job má definován Step a ten Tasklet. Tasklet odkazuje na třídu implementující rozhraní Tasklet.
MyTasklet.java
package cz.vitfo;
import org.springframework.batch.core.StepContribution;
import org.springframework.batch.core.scope.context.ChunkContext;
import org.springframework.batch.core.step.tasklet.Tasklet;
import org.springframework.batch.repeat.RepeatStatus;
public class MyTasklet implements Tasklet {
public RepeatStatus execute(StepContribution arg0, ChunkContext arg1) throws Exception {
System.out.println("Code in " + this.getClass().getSimpleName() + " is executed.");
return null;
}
}
Třída, která implementuje rozhraní Tasklet. Jediným jejím úkolem je vypsat text.
ExecuteJob.java
package cz.vitfo;
import org.springframework.batch.core.Job;
import org.springframework.batch.core.JobExecution;
import org.springframework.batch.core.JobParameters;
import org.springframework.batch.core.launch.JobLauncher;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class ExecuteJob {
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("context.xml");
JobLauncher jobLauncher = (JobLauncher) context.getBean("jobLauncher");
Job job = (Job) context.getBean("myJob");
try {
JobExecution execution = jobLauncher.run(job, new JobParameters());
System.out.println("Exit Status: " + execution.getStatus());
System.out.println("Start: " + execution.getStartTime());
System.out.println("End: " + execution.getEndTime());
} catch (Exception e) {
e.printStackTrace();
} finally {
if (context != null) {
context = null;
}
}
System.out.println("Done");
}
}
Nejdříve načteme kontext. Poté z něj získáme JobLauncher a Job. Tento Job spustíme pomocí JobLauncher a vypíšeme status jobu po spuštění.
Výsledek
Code in MyTasklet is executed.
Exit Status: COMPLETED
Start: Tue Nov 01 17:26:15 CET 2016
End: Tue Nov 01 17:26:15 CET 2016
Done