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