Beispiel für Spring Batch

Willkommen beim Spring Batch Beispiel. Spring Batch ist ein Modul des Spring Frameworks zur Ausführung von Stapelaufträgen. Wir können Spring Batch verwenden, um eine Reihe von Aufträgen zu verarbeiten.

Spring Batch Beispiel

Bevor wir das Beispielprogramm für Spring Batch durchgehen, erhalten wir eine Vorstellung von den Spring Batch-Terminologien.

  • A job can consist of ‘n’ number of steps. Each step contains Read-Process-Write task or it can have single operation, which is called tasklet.
  • Read-Process-Write bedeutet im Wesentlichen, aus einer Quelle wie einer Datenbank, einer CSV-Datei usw. zu lesen, die Daten zu verarbeiten und sie in eine Quelle wie eine Datenbank, eine CSV-Datei, eine XML-Datei usw. zu schreiben.
  • Tasklet bedeutet die Ausführung einer einzelnen Aufgabe oder Operation, wie das Bereinigen von Verbindungen, das Freigeben von Ressourcen nach abgeschlossener Verarbeitung.
  • Read-Process-Write und Tasklets können miteinander verkettet werden, um einen Auftrag auszuführen.

Spring Batch Beispiel

Lassen Sie uns ein Arbeitsbeispiel für die Implementierung von Spring Batch betrachten. Wir werden das folgende Szenario für die Implementierungszwecke berücksichtigen. Eine CSV-Datei mit Daten muss als XML konvertiert werden, wobei die Daten und Tags nach dem Spaltennamen benannt werden. Unten sind die wichtigen Tools und Bibliotheken, die für das Spring Batch Beispiel verwendet werden.

  1. Apache Maven 3.5.0 – für Projektbau und Abhängigkeitsverwaltung.
  2. Eclipse Oxygen Release 4.7.0 – IDE zur Erstellung von Spring Batch Maven-Anwendungen.
  3. Java 1.8
  4. Spring Core 4.3.12.RELEASE
  5. Spring OXM 4.3.12.RELEASE
  6. Spring JDBC 4.3.12.RELEASE
  7. Spring Batch 3.0.8.RELEASE
  8. MySQL Java-Treiber 5.1.25 – verwenden Sie ihn entsprechend Ihrer MySQL-Installation. Dies ist für die Spring Batch-Metadatentabellen erforderlich.

Verzeichnisstruktur für Spring Batch-Beispiel

Das folgende Bild veranschaulicht alle Komponenten unseres Spring Batch-Beispielprojekts.

Spring Batch Maven-Abhängigkeiten

Im Folgenden finden Sie den Inhalt der pom.xml-Datei mit allen erforderlichen Abhängigkeiten für unser Spring Batch-Beispielprojekt.

<project xmlns="https://maven.apache.org/POM/4.0.0" xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="https://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
	<modelVersion>4.0.0</modelVersion>

	<groupId>com.journaldev.spring</groupId>
	<artifactId>SpringBatchExample</artifactId>
	<version>0.0.1-SNAPSHOT</version>
	<packaging>jar</packaging>

	<name>SpringBatchDemo</name>
	<url>https://maven.apache.org</url>

	<properties>
		<jdk.version>1.8</jdk.version>
		<spring.version>4.3.12.RELEASE</spring.version>
		<spring.batch.version>3.0.8.RELEASE</spring.batch.version>
		<mysql.driver.version>5.1.25</mysql.driver.version>
		<junit.version>4.11</junit.version>
	</properties>

	<dependencies>

		<!-- Spring Core -->
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-core</artifactId>
			<version>${spring.version}</version>
		</dependency>

		<!-- Spring jdbc, for database -->
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-jdbc</artifactId>
			<version>${spring.version}</version>
		</dependency>

		<!-- Spring XML to/back object -->
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-oxm</artifactId>
			<version>${spring.version}</version>
		</dependency>

		<!-- MySQL database driver -->
		<dependency>
			<groupId>mysql</groupId>
			<artifactId>mysql-connector-java</artifactId>
			<version>${mysql.driver.version}</version>
		</dependency>

		<!-- Spring Batch 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>

		<!-- Spring Batch unit test -->
		<dependency>
			<groupId>org.springframework.batch</groupId>
			<artifactId>spring-batch-test</artifactId>
			<version>${spring.batch.version}</version>
		</dependency>

		<!-- Junit -->
		<dependency>
			<groupId>junit</groupId>
			<artifactId>junit</artifactId>
			<version>${junit.version}</version>
			<scope>test</scope>
		</dependency>

		<dependency>
			<groupId>com.thoughtworks.xstream</groupId>
			<artifactId>xstream</artifactId>
			<version>1.4.10</version>
		</dependency>

	</dependencies>
	<build>
		<finalName>spring-batch</finalName>
		<plugins>
			<plugin>
				<groupId>org.apache.maven.plugins</groupId>
				<artifactId>maven-eclipse-plugin</artifactId>
				<version>2.9</version>
				<configuration>
					<downloadSources>true</downloadSources>
					<downloadJavadocs>false</downloadJavadocs>
				</configuration>
			</plugin>
			<plugin>
				<groupId>org.apache.maven.plugins</groupId>
				<artifactId>maven-compiler-plugin</artifactId>
				<version>2.3.2</version>
				<configuration>
					<source>${jdk.version}</source>
					<target>${jdk.version}</target>
				</configuration>
			</plugin>
		</plugins>
	</build>
</project>

Spring Batch Verarbeitung von CSV-Eingabedateien

Hier ist der Inhalt unserer Beispieldatei im CSV-Format für die Spring Batch Verarbeitung.

1001,Tom,Moody, 29/7/2013
1002,John,Parker, 30/7/2013
1003,Henry,Williams, 31/7/2013

Spring Batch Job Konfiguration

Wir müssen eine Frühlingsbohne und einen Spring Batch-Job in einer Konfigurationsdatei definieren. Nachfolgend finden Sie der Inhalt der Datei job-batch-demo.xml, die den wichtigsten Teil des Spring Batch-Projekts darstellt.

<beans xmlns="https://www.springframework.org/schema/beans"
	xmlns:batch="https://www.springframework.org/schema/batch" xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="https://www.springframework.org/schema/batch
		https://www.springframework.org/schema/batch/spring-batch-3.0.xsd
		https://www.springframework.org/schema/beans 
		https://www.springframework.org/schema/beans/spring-beans-4.3.xsd
	">

	<import resource="../config/context.xml" />
	<import resource="../config/database.xml" />

	<bean id="report" class="com.journaldev.spring.model.Report"
		scope="prototype" />
	<bean id="itemProcessor" class="com.journaldev.spring.CustomItemProcessor" />

	<batch:job id="DemoJobXMLWriter">
		<batch:step id="step1">
			<batch:tasklet>
				<batch:chunk reader="csvFileItemReader" writer="xmlItemWriter"
					processor="itemProcessor" commit-interval="10">
				</batch:chunk>
			</batch:tasklet>
		</batch:step>
	</batch:job>

	<bean id="csvFileItemReader" class="org.springframework.batch.item.file.FlatFileItemReader">

		<property name="resource" value="classpath:csv/input/report.csv" />

		<property name="lineMapper">
			<bean class="org.springframework.batch.item.file.mapping.DefaultLineMapper">
				<property name="lineTokenizer">
					<bean
						class="org.springframework.batch.item.file.transform.DelimitedLineTokenizer">
						<property name="names" value="id,firstname,lastname,dob" />
					</bean>
				</property>
				<property name="fieldSetMapper">
					<bean class="com.journaldev.spring.ReportFieldSetMapper" />

					<!-- if no data type conversion, use BeanWrapperFieldSetMapper to map 
						by name <bean class="org.springframework.batch.item.file.mapping.BeanWrapperFieldSetMapper"> 
						<property name="prototypeBeanName" value="report" /> </bean> -->
				</property>
			</bean>
		</property>

	</bean>

	<bean id="xmlItemWriter" class="org.springframework.batch.item.xml.StaxEventItemWriter">
		<property name="resource" value="file:xml/outputs/report.xml" />
		<property name="marshaller" ref="reportMarshaller" />
		<property name="rootTagName" value="report" />
	</bean>

	<bean id="reportMarshaller" class="org.springframework.oxm.jaxb.Jaxb2Marshaller">
		<property name="classesToBeBound">
			<list>
				<value>com.journaldev.spring.model.Report</value>
			</list>
		</property>
	</bean>

</beans>
  1. Wir verwenden FlatFileItemReader, um die CSV-Datei zu lesen, CustomItemProcessor, um die Daten zu verarbeiten, und schreiben sie mit StaxEventItemWriter in eine XML-Datei.
  2. batch:job – Dieses Tag definiert den Job, den wir erstellen möchten. Die ID-Eigenschaft gibt die ID des Jobs an. Wir können mehrere Jobs in einer einzigen XML-Datei definieren.
  3. batch:step – Dieses Tag wird verwendet, um verschiedene Schritte eines Spring Batch-Jobs zu definieren.
  4. Zwei verschiedene Arten von Verarbeitungsstilen werden vom Spring Batch Framework angeboten, nämlich „TaskletStep Oriented“ und „Chunk Oriented“. Der Chunk-Oriented-Stil, der in diesem Beispiel verwendet wird, bezieht sich darauf, die Daten einzeln zu lesen und ‚Chunks‘ zu erstellen, die innerhalb einer Transaktionsgrenze geschrieben werden.
  5. reader: Spring Bean, der zum Lesen der Daten verwendet wird. In diesem Beispiel haben wir das csvFileItemReader-Bean verwendet, das eine Instanz von FlatFileItemReader ist.
  6. processor: Dies ist die Klasse, die zum Verarbeiten der Daten verwendet wird. In diesem Beispiel haben wir CustomItemProcessor verwendet.
  7. writer: Bean, der verwendet wird, um Daten in eine XML-Datei zu schreiben.
  8. commit-interval: Diese Eigenschaft definiert die Größe des Chunks, der einmal die Verarbeitung abgeschlossen ist, committed wird. Im Wesentlichen bedeutet dies, dass der ItemReader die Daten einzeln liest und der ItemProcessor sie auf die gleiche Weise verarbeitet, aber der ItemWriter die Daten nur schreibt, wenn sie die Größe des Commit-Intervalls erreichen.
  9. Drei wichtige Schnittstellen, die im Rahmen dieses Projekts verwendet werden, sind ItemReader, ItemProcessor und ItemWriter aus dem Paket org.springframework.batch.item.

Spring Batch Model Class

Zuerst lesen wir die CSV-Datei in ein Java-Objekt ein und verwenden dann JAXB, um sie in eine XML-Datei zu schreiben. Hier ist unsere Model-Klasse mit den erforderlichen JAXB Annotations.

package com.journaldev.spring.model;

import java.util.Date;

import javax.xml.bind.annotation.XmlAttribute;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;

@XmlRootElement(name = "record")
public class Report {

	private int id;
	private String firstName;
	private String lastName;
	private Date dob;

	@XmlAttribute(name = "id")
	public int getId() {
		return id;
	}

	public void setId(int id) {
		this.id = id;
	}

	@XmlElement(name = "firstname")
	public String getFirstName() {
		return firstName;
	}

	public void setFirstName(String firstName) {
		this.firstName = firstName;
	}

	@XmlElement(name = "lastname")
	public String getLastName() {
		return lastName;
	}

	public void setLastName(String lastName) {
		this.lastName = lastName;
	}

	@XmlElement(name = "dob")
	public Date getDob() {
		return dob;
	}

	public void setDob(Date dob) {
		this.dob = dob;
	}

	@Override
	public String toString() {
		return "Report [id=" + id + ", firstname=" + firstName + ", lastName=" + lastName + ", DateOfBirth=" + dob
				+ "]";
	}

}

Beachten Sie, dass die Felder der Model-Klasse mit denen in der Spring Batch Mapper-Konfiguration übereinstimmen sollten, d. h. property name="names" value="id,firstname,lastname,dob" in unserem Fall.

Spring Batch FieldSetMapper

A custom FieldSetMapper is needed to convert a Date. If no data type conversion is required, then only BeanWrapperFieldSetMapper should be used to map the values by name automatically. The java class which extends FieldSetMapper is ReportFieldSetMapper.

package com.journaldev.spring;

import java.text.ParseException;
import java.text.SimpleDateFormat;

import org.springframework.batch.item.file.mapping.FieldSetMapper;
import org.springframework.batch.item.file.transform.FieldSet;
import org.springframework.validation.BindException;

import com.journaldev.spring.model.Report;

public class ReportFieldSetMapper implements FieldSetMapper {

	private SimpleDateFormat dateFormat = new SimpleDateFormat("dd/MM/yyyy");

	public Report mapFieldSet(FieldSet fieldSet) throws BindException {

		Report report = new Report();
		report.setId(fieldSet.readInt(0));
		report.setFirstName(fieldSet.readString(1));
		report.setLastName(fieldSet.readString(2));

		// Standardformat yyyy-MM-dd
		// fieldSet.readDate(4);
		String date = fieldSet.readString(3);
		try {
			report.setDob(dateFormat.parse(date));
		} catch (ParseException e) {
			e.printStackTrace();
		}

		return report;

	}

}

Spring Batch Item Processor

Wie in der Job-Konfiguration festgelegt, wird ein ItemProcessor vor dem ItemWriter ausgeführt. Wir haben eine Klasse CustomItemProcessor.java dafür erstellt.

package com.journaldev.spring;

import org.springframework.batch.item.ItemProcessor;

import com.journaldev.spring.model.Report;

public class CustomItemProcessor implements ItemProcessor<Report, Report> {

	public Report process(Report item) throws Exception {
		
		System.out.println("Processing..." + item);
		String fname = item.getFirstName();
		String lname = item.getLastName();
		
		item.setFirstName(fname.toUpperCase());
		item.setLastName(lname.toUpperCase());
		return item;
	}

}

Wir können Daten in der ItemProcessor-Implementierung manipulieren, wie Sie sehen können, dass ich Vor- und Nachnamen in Großbuchstaben umwandle.

Spring-Konfigurationsdateien

In unserer Spring-Batch-Konfigurationsdatei haben wir zwei zusätzliche Konfigurationsdateien importiert – context.xml und database.xml.

<beans xmlns="https://www.springframework.org/schema/beans"
	xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="
		https://www.springframework.org/schema/beans 
		https://www.springframework.org/schema/beans/spring-beans-4.3.xsd">

	<!-- stored job-meta in memory -->
	<!--  
	<bean id="jobRepository"
		class="org.springframework.batch.core.repository.support.MapJobRepositoryFactoryBean">
		<property name="transactionManager" ref="transactionManager" />
	</bean>
 	 -->
 	 
 	 <!-- stored job-meta in database -->
	<bean id="jobRepository"
		class="org.springframework.batch.core.repository.support.JobRepositoryFactoryBean">
		<property name="dataSource" ref="dataSource" />
		<property name="transactionManager" ref="transactionManager" />
		<property name="databaseType" value="mysql" />
	</bean>
	
	<bean id="transactionManager"
		class="org.springframework.batch.support.transaction.ResourcelessTransactionManager" />
	 
	<bean id="jobLauncher"
		class="org.springframework.batch.core.launch.support.SimpleJobLauncher">
		<property name="jobRepository" ref="jobRepository" />
	</bean>

</beans>
  • jobRepository – Das JobRepository ist dafür verantwortlich, jedes Java-Objekt in seine richtige Metadatentabelle für Spring Batch zu speichern.
  • transactionManager – Dies ist dafür verantwortlich, die Transaktion zu bestätigen, sobald die Größe des Commit-Intervalls und die verarbeiteten Daten gleich sind.
  • jobLauncher – Dies ist das Herzstück von Spring Batch. Diese Schnittstelle enthält die Run-Methode, die verwendet wird, um den Job auszulösen.
<beans xmlns="https://www.springframework.org/schema/beans"
	xmlns:jdbc="https://www.springframework.org/schema/jdbc" xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="https://www.springframework.org/schema/beans 
		https://www.springframework.org/schema/beans/spring-beans-4.3.xsd
		https://www.springframework.org/schema/jdbc 
		https://www.springframework.org/schema/jdbc/spring-jdbc-4.3.xsd">

	<!-- connect to database -->
	<bean id="dataSource"
		class="org.springframework.jdbc.datasource.DriverManagerDataSource">
		<property name="driverClassName" value="com.mysql.jdbc.Driver" />
		<property name="url" value="jdbc:mysql://localhost:3306/Test" />
		<property name="username" value="test" />
		<property name="password" value="test123" />
	</bean>

	<bean id="transactionManager"
		class="org.springframework.batch.support.transaction.ResourcelessTransactionManager" />

	<!-- create job-meta tables automatically -->
	<!-- <jdbc:initialize-database data-source="dataSource"> <jdbc:script location="org/springframework/batch/core/schema-drop-mysql.sql" 
		/> <jdbc:script location="org/springframework/batch/core/schema-mysql.sql" 
		/> </jdbc:initialize-database> -->
</beans>

Spring Batch verwendet einige Metadatentabellen, um Informationen zu Batch-Jobs zu speichern. Wir können sie aus den Spring-Batch-Konfigurationen erstellen lassen, aber es ist ratsam, dies manuell durch Ausführen der SQL-Dateien zu tun, wie im kommentierten Code oben zu sehen ist. Aus Sicherheitssicht ist es besser, dem Spring-Batch-Datenbankbenutzer keinen DDL-Ausführungszugriff zu geben.

Spring Batch-Tabellen

Spring Batch-Tabellen entsprechen den Domain-Objekten, die sie in Java darstellen, sehr genau. Zum Beispiel – JobInstance, JobExecution, JobParameters und StepExecution werden jeweils BATCH_JOB_INSTANCE, BATCH_JOB_EXECUTION, BATCH_JOB_EXECUTION_PARAMS und BATCH_STEP_EXECUTION zugeordnet. ExecutionContext wird sowohl BATCH_JOB_EXECUTION_CONTEXT als auch BATCH_STEP_EXECUTION_CONTEXT zugeordnet. Das JobRepository ist dafür verantwortlich, jedes Java-Objekt in seine richtige Tabelle zu speichern und zu speichern. Nachfolgend finden Sie die Details jeder Metadatentabelle.

  1. Batch_job_instance: Die Tabelle BATCH_JOB_INSTANCE enthält alle relevanten Informationen zu einer JobInstance.
  2. Batch_job_execution_params: Die Tabelle BATCH_JOB_EXECUTION_PARAMS enthält alle relevanten Informationen zum JobParameters-Objekt.
  3. Batch_job_execution: Die Tabelle BATCH_JOB_EXECUTION enthält Daten zum JobExecution-Objekt. Eine neue Zeile wird jedes Mal hinzugefügt, wenn ein Job ausgeführt wird.
  4. Batch_step_execution: Die Tabelle BATCH_STEP_EXECUTION enthält alle relevanten Informationen zum StepExecution-Objekt.
  5. Batch_job_execution_context: Die Tabelle BATCH_JOB_EXECUTION_CONTEXT enthält Daten zum ExecutionContext eines Jobs. Für jede JobExecution gibt es genau einen Job-ExecutionContext, der alle jobbezogenen Daten enthält, die für diese bestimmte Jobausführung benötigt werden. Diese Daten stellen typischerweise den Zustand dar, der nach einem Fehler abgerufen werden muss, damit eine JobInstance von dem Punkt aus neu gestartet werden kann, an dem sie fehlgeschlagen ist.
  6. Batch_step_execution_context: Die Tabelle BATCH_STEP_EXECUTION_CONTEXT enthält Daten, die für den ExecutionContext eines Schritts relevant sind. Für jede StepExecution gibt es genau einen ExecutionContext, der alle Daten enthält, die für eine bestimmte Schrittausführung gespeichert werden müssen. Diese Daten stellen typischerweise den Zustand dar, der nach einem Fehler wiederhergestellt werden muss, damit eine JobInstance von dem Punkt aus neu gestartet werden kann, an dem der Fehler aufgetreten ist.
  7. Batch_job_execution_seq: Diese Tabelle enthält die Daten zur Ausführungsreihenfolge des Jobs.
  8. Batch_step_execution_seq: Diese Tabelle enthält die Daten zur Sequenz für die Schrittausführung.
  9. Batch_job_seq: Diese Tabelle enthält die Daten zur Reihenfolge des Jobs. Falls wir mehrere Jobs haben, erhalten wir mehrere Zeilen.

Spring Batch Testprogramm

Unser Beispielprojekt für Spring Batch ist fertig. Der letzte Schritt besteht darin, eine Testklasse zu schreiben, um es als Java-Programm auszuführen.

package com.journaldev.spring;

import org.springframework.batch.core.Job;
import org.springframework.batch.core.JobExecution;
import org.springframework.batch.core.JobParameters;
import org.springframework.batch.core.JobParametersBuilder;
import org.springframework.batch.core.launch.JobLauncher;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class App {
	public static void main(String[] args) {

		String[] springConfig = { "spring/batch/jobs/job-batch-demo.xml" };

		ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext(springConfig);

		JobLauncher jobLauncher = (JobLauncher) context.getBean("jobLauncher");
		Job job = (Job) context.getBean("DemoJobXMLWriter");

		JobParameters jobParameters = new JobParametersBuilder().addLong("time", System.currentTimeMillis())
				.toJobParameters();

		try {

			JobExecution execution = jobLauncher.run(job, jobParameters);
			System.out.println("Exit Status : " + execution.getStatus());

		} catch (Exception e) {
			e.printStackTrace();
		}

		System.out.println("Done");
		context.close();
	}
}

Führen Sie einfach das obige Programm aus, und Sie erhalten eine Ausgabe-XML wie unten angegeben.

<?xml version="1.0" encoding="UTF-8"?><report><record id="1001"><dob>2013-07-29T00:00:00+05:30</dob><firstname>TOM</firstname><lastname>MOODY</lastname></record><record id="1002"><dob>2013-07-30T00:00:00+05:30</dob><firstname>JOHN</firstname><lastname>PARKER</lastname></record><record id="1003"><dob>2013-07-31T00:00:00+05:30</dob><firstname>HENRY</firstname><lastname>WILLIAMS</lastname></record></report>

Das ist alles für das Beispiel Spring Batch. Sie können das endgültige Projekt über den untenstehenden Link herunterladen.

Spring Batch Beispielprojekt herunterladen

Referenz: Offizieller Leitfaden

Source:
https://www.digitalocean.com/community/tutorials/spring-batch-example