Willkommen beim Spring Batch Beispiel

Spring Batch ist ein Modul des Spring Frameworks für die Ausführung von Batch-Jobs. Wir können Spring Batch verwenden, um eine Serie von Jobs zu verarbeiten.

Übersicht über das Beispiel

Bevor wir das Beispielprogramm durchgehen, lasst uns einige Ideen über die Terminologien von Spring Batch sammeln.

Verstehen von Jobs und Schritten

Ein Job kann aus ’n‘ Anzahl von Schritten bestehen. Jeder Schritt enthält eine Lese-Verarbeitungs-Schreib-Aufgabe, oder er kann eine einzelne Operation haben, die als Tasklet bezeichnet wird.

Lese-Verarbeitungs-Schreiben bedeutet im Wesentlichen das Lesen von einer Quelle wie einer Datenbank, CSV usw., dann das Verarbeiten der Daten und das Schreiben auf eine Quelle wie Datenbank, CSV, XML usw.

Ein Tasklet bedeutet die Durchführung einer einzelnen Aufgabe oder Operation, wie z.B. das Reinigen von Verbindungen, das Freigeben von Ressourcen nach Abschluss der Verarbeitung.

Lese-Verarbeitungs-Schreiben und Tasklets können zusammengekettet werden, um einen Job auszuführen.

Implementierung von Spring Batch: Ein praktisches Beispiel

Betrachten wir ein praktisches Beispiel für die Implementierung. Wir werden das folgende Szenario für die Implementierung in Betracht ziehen: Eine CSV-Datei mit Daten soll in XML konvertiert werden, wobei die Daten und Tags nach dem Spaltennamen benannt werden.

Im Folgenden sind die wichtigen Werkzeuge und Bibliotheken aufgeführt, die für das Spring Batch Beispiel verwendet werden:

  • Apache Maven 3.5.0 – für Projektbau und Abhängigkeitsmanagement.
  • Eclipse Oxygen Release 4.7.0 – IDE für die Erstellung einer Spring Batch Maven-Anwendung.
  • Java 1.8
  • Spring Core 4.3.12.RELEASE
  • Spring OXM 4.3.12.RELEASE
  • Spring JDBC 4.3.12.RELEASE
  • Spring Batch 3.0.8.RELEASE
  • MySQL Java Treiber 5.1.25 – verwenden Sie basierend auf Ihrer MySQL-Installation. Dies ist erforderlich für die Spring Batch Metadatentabellen.

Spring Batch Maven-Abhängigkeiten

Im Folgenden der Inhalt der pom.xml-Datei mit allen erforderlichen Abhängigkeiten für unser 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 der CSV-Eingabedatei

Hier ist der Inhalt unserer Beispiel-CSV-Datei zur Verarbeitung.

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

Spring Batch Jobkonfiguration

Wir müssen Spring Bean und Spring Batch Job in einer Konfigurationsdatei definieren. Nachfolgend der Inhalt der Datei job-batch-demo.xml, es ist der wichtigste Teil unseres Projekts.

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

Spring Batch Modelklasse

Zuerst lesen wir die CSV-Datei in ein Java-Objekt ein und dann verwenden wir JAXB, um sie in eine XML-Datei zu schreiben. Nachfolgend unsere Modelklasse mit den erforderlichen JAXB-Annotationen.

package com.journaldev.spring.model;

import javax.xml.bind.annotation.XmlAttribute;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
import java.util.Date;

@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 + "]";
    }
}

FieldSetMapper

Ein benutzerdefinierter FieldSetMapper ist notwendig, um ein Datum umzuwandeln. Wenn keine Datentypumwandlung erforderlich ist, sollte nur der BeanWrapperFieldSetMapper verwendet werden, um die Werte automatisch nach Namen zuzuordnen. Die Java-Klasse, die FieldSetMapper erweitert, ist ReportFieldSetMapper.

package com.journaldev.spring;

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;
import java.text.ParseException;
import java.text.SimpleDateFormat;

public class ReportFieldSetMapper implements FieldSetMapper<Report> {

    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));

        // default format 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 Jobkonfiguration definiert, wird ein itemProcessor vor dem itemWriter ausgeführt. Wir haben eine Klasse CustomItemProcessor.java für diesen Zweck 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 im ItemProcessor bearbeiten, wie Sie sehen können, indem ich die Werte für Vornamen 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 verantwortlich für das Speichern jedes Java-Objekts in der entsprechenden Meta-Daten-Tabelle für Spring Batch.
  • transactionManager: ist verantwortlich für das Commit der Transaktion, 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.

Spring Batch Datenbankkonfiguration

Unten finden Sie die Konfiguration für die Datenbank, die in Spring Batch verwendet wird.

<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 über 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 Sie im kommentierten Code oben sehen können. Aus Sicherheitsgründen ist es besser, dem Spring Batch-Datenbankbenutzer keinen DDL-Ausführungszugriff zu gewähren.

Spring Batch Tabellen

Die Spring Batch Tabellen entsprechen sehr genau den Domain-Objekten, die sie in Java repräsentieren. Zum Beispiel entsprechen JobInstance, JobExecution, JobParameters und StepExecution den Tabellen BATCH_JOB_INSTANCE, BATCH_JOB_EXECUTION, BATCH_JOB_EXECUTION_PARAMS und BATCH_STEP_EXECUTION. ExecutionContext entspricht sowohl BATCH_JOB_EXECUTION_CONTEXT als auch BATCH_STEP_EXECUTION_CONTEXT. Das JobRepository ist verantwortlich für das Speichern und Speichern jedes Java-Objekts in seiner korrekten Tabelle.

Nachfolgend sind die Details jeder Metadaten-Tabelle aufgeführt:

  • Batch_job_instance: Die Tabelle BATCH_JOB_INSTANCE enthält alle relevanten Informationen zu einem JobInstance.
  • Batch_job_execution_params: Die Tabelle BATCH_JOB_EXECUTION_PARAMS enthält alle relevanten Informationen zum JobParameters-Objekt.
  • Batch_job_execution: Die Tabelle BATCH_JOB_EXECUTION enthält Daten, die zum JobExecution-Objekt gehören. Eine neue Zeile wird jedes Mal hinzugefügt, wenn ein Job ausgeführt wird.
  • Batch_step_execution: Die Tabelle BATCH_STEP_EXECUTION enthält alle relevanten Informationen zum StepExecution-Objekt.
  • Batch_job_execution_context: Die Tabelle BATCH_JOB_EXECUTION_CONTEXT enthält Daten, die zum ExecutionContext eines Jobs gehören. Es gibt genau einen Job ExecutionContext für jede JobExecution, und er enthält alle job-spezifischen Daten, die für diese bestimmte Jobausführung benötigt werden. Diese Daten stellen in der Regel den Zustand dar, der nach einem Fehler wiederhergestellt werden muss, damit eine JobInstance dort neu starten kann, wo sie fehlgeschlagen ist.
  • Batch_step_execution_context: Die Tabelle BATCH_STEP_EXECUTION_CONTEXT enthält Daten, die zum ExecutionContext eines Schritts gehören. Es gibt genau einen ExecutionContext für jede StepExecution, und er enthält alle Daten, die für eine bestimmte Schrittausführung gespeichert werden müssen. Diese Daten stellen in der Regel den Zustand dar, der nach einem Fehler wiederhergestellt werden muss, damit eine JobInstance dort neu starten kann, wo sie fehlgeschlagen ist.
  • Batch_job_execution_seq: Diese Tabelle enthält die Daten zur Ausführungssequenz von Jobs.
  • Batch_step_execution_seq: Diese Tabelle enthält die Daten zur Sequenz für Schrittausführungen.
  • Batch_job_seq: Diese Tabelle enthält die Daten zur Jobsequenz, falls mehrere Jobs vorhanden sind, gibt es mehrere Zeilen.

Spring Batch Testprogramm

Unser Spring Batch Beispielprojekt ist fertig, der letzte Schritt ist es, 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 oben genannte Programm aus, und Sie erhalten eine Ausgabe-XML wie unten.

<?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 Spring Batch Beispiel – eine Anleitung – Willkommen beim Spring Batch

Kostenlosen Account erstellen

Registrieren Sie sich jetzt und erhalten Sie Zugang zu unseren Cloud Produkten.

Das könnte Sie auch interessieren: