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.
- naplníme konvici vodou
- zapneme konvici
- dáme do konvice čaj
- počkáme tři minuty
- 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).
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>
V tomto souboru jsou definice bean jobRepository, jobLauncher a transactionManager.
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 definition --> <beans:bean id="fillKettleWithWater" class="cz.vitfo.tasklets.FillKettleWithWater"/> <beans:bean id="turnOnKettle" class="cz.vitfo.tasklets.TurnOnKettle"/> <beans:bean id="putTeaToWater" class="cz.vitfo.tasklets.PutTeaToWater"/> <beans:bean id="waitThreeMinutes" class="cz.vitfo.tasklets.WaitThreeMinutes"/> <beans:bean id="serveTea" class="cz.vitfo.tasklets.ServeTea"/> <!-- Job definition --> <job id="prepareTeaJob"> <step id="fillKetleWitWaterStep" next="turnOnKettleStep"> <tasklet ref="fillKettleWithWater"/> </step> <step id="turnOnKettleStep" next="putTeaToWaterStep"> <tasklet ref="turnOnKettle"/> </step> <step id="putTeaToWaterStep" next="waitThreeMinutesStep"> <tasklet ref="putTeaToWater"/> </step> <step id="waitThreeMinutesStep" next="serveTeaStep"> <tasklet ref="waitThreeMinutes"/> </step> <step id="serveTeaStep"> <tasklet ref="serveTea"/> </step> </job> </beans:beans>
Zde definujeme job, jeho jednotlivé kroky a v nich úkoly. Třída představující tasklet musí implementovat rozhraní Tasklet a logiku definovat v metodě execute(). Celkem budeme používat pět taskletů.
FillKettleWithWater.java
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 FillKettleWithWater implements Tasklet {
public RepeatStatus execute(StepContribution contribution, ChunkContext chunkContext) throws Exception {
System.out.println("Filling kettle with the water.");
return null;
}
}
TurnOnKettle.java
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 TurnOnKettle implements Tasklet {
public RepeatStatus execute(StepContribution contribution, ChunkContext chunkContext) throws Exception {
System.out.println("Turning the kettle on.");
return null;
}
}
PutTeaToWater.java
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 PutTeaToWater implements Tasklet {
public RepeatStatus execute(StepContribution contribution, ChunkContext chunkContext) throws Exception {
System.out.println("Putting delicious tea to the hot water.");
return null;
}
}
WaitThreeMinutes.java
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 WaitThreeMinutes implements Tasklet {
public RepeatStatus execute(StepContribution contribution, ChunkContext chunkContext) throws Exception {
System.out.println("Waiting for three minutes to infuse tea.");
return null;
}
}
ServeTea.java
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 ServeTea implements Tasklet {
public RepeatStatus execute(StepContribution contribution, ChunkContext chunkContext) throws Exception {
System.out.println("Serving the tea.");
return null;
}
}
Všechny tasklety jsou jednoduché a jediné co dělají je, že do konzole vytisknou text.
Nakonec nám zbývá třída s metodou main, ve které vytvoříme kontext, pomocí JobLancher spustíme job a zobrazíme JobExecution status.
ExecuteJob.java
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) {
String[] springConfig = {"job.xml"};
ApplicationContext context = new ClassPathXmlApplicationContext(springConfig);
JobLauncher jobLauncher = (JobLauncher) context.getBean("jobLauncher");
Job job = (Job) context.getBean("prepareTeaJob");
try {
JobExecution execution = jobLauncher.run(job, new JobParameters());
System.out.println("Exit Status: " + execution.getStatus());
} catch (Exception e) {
e.printStackTrace();
} finally {
if (context != null) {
context = null;
}
}
System.out.println("Done");
}
}
Výsledek spuštění.
Filling kettle with the water. Turning the kettle on. Putting delicious tea to the hot water. Waiting for three minutes to infuse tea. Serving the tea. Exit Status: COMPLETED Done