Spring Batch 3. díl

V minulém díle jsme si vytvořili job, který obsahoval několik kroků (Step). Každému kroku byl přiřazen jeden tasklet, který implementoval celou funkcionalitu. Dost často ale krok v jobu bude načítat data, zpracovávat je a nakonec zapisovat. Pro tento případ je tady chunk. V rámci chunku je možné definovat reader, processor a writer.

<chunk reader="myReader" writer="myWriter" processor="myProcessor">

V následujícím příkladu si ukážeme job, který se bude skládat z jediného kroku, během kterého zavoláme náš reader, poté data vrácená z readeru zpracujeme ve vlastním processoru a nakonec data zapíšem writerem.

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: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:beans>

job.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:import resource="context.xml" />
	
	<beans:bean id="myReader" class="cz.vitfo.MyReader"/>
	<beans:bean id="myProcessor" class="cz.vitfo.MyProcessor"/>
	<beans:bean id="myWriter" class="cz.vitfo.MyWriter"/>
	
	<job id="myJob">
		<step id="myStep">
			<tasklet>
				<chunk reader="myReader" writer="myWriter" processor="myProcessor" commit-interval="4"/>
			</tasklet>
		</step>
	</job>
</beans:beans>

Třída MyInput představuje objekty, které budou načítány (vraceny) readerem.

Číst dál

Spring Batch 2. díl

V předchozím díle jsme se věnovali představení frameworku String Batch, vysvětlení základních pojmů a ukázali jsme si jednoduchý projekt. V tomto díle vytvoříme další projekt.

Job je posloupnost jednotlivých kroků (Step). Krok pak obsahuje úkol (Tasklet), který popisuje (implementuje) co se má dělat. Task v sobě ještě může obsahovat další kousek (Chunk), ale tomu se budemě věnovat někdy příště.

Vaříme čaj se Spring Batch.
V následujícím příkladu si ukážeme job, který se bude skládat s pěti kroků (Tasklet). Budeme připravovat čaj.

  1. naplníme konvici vodou
  2. zapneme konvici
  3. dáme do konvice čaj
  4. počkáme tři minuty
  5. hotový čaj naservírujeme

Struktura projektu

│   pom.xml
│
└───src
    ├───main
    │   └───java
    │       └───cz
    │           └───vitfo
    │               │   ExecuteJob.java
    │               │
    │               └───tasklets
    │                       FillKettleWithWater.java
    │                       PutTeaToWater.java
    │                       ServeTea.java
    │                       TurnOnKettle.java
    │                       WaitThreeMinutes.java
    │
    └───resources
            context.xml
            job.xml


Všimněte si, že ve složce resources máme dva xml. Spring umožňuje rozdělit konfiguraci do více souborů. Jednou z možností je potom pro vytvoření kontextu předat list konfiguračních souboru (ukázáno v tomto příspěvku) a nebo importovat jeden konfigurační soubor do druhého pomocí elementu <import> jak je ukázáno v tomto příkladu (řádek osm v souboru job.xml).

Číst dál

Spring Batch 1. díl

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