Java Batch Tutorial

In de wereld van vandaag heeft internet de manier waarop we ons leven leiden veranderd en een van de belangrijkste redenen daarvoor is het gebruik van internet voor de meeste van de dagelijkse karweitjes. Dit heeft geleid tot enorme hoeveelheden gegevens die beschikbaar zijn voor verwerking.

Enkele van de voorbeelden waarbij het om enorme hoeveelheden gegevens gaat, zijn de verwerking van loonstrookjes, bankafschriften, renteberekening, enz. Dus stel je voor dat al deze banen moesten handmatig worden gedaan, zal het eeuwen duren om deze banen af te maken.

Hoe wordt het gedaan in de huidige tijd? Het antwoord is Batch Processing.

Inleiding

Batch processing wordt uitgevoerd op bulk data, zonder handmatige tussenkomst, en langlopende. Het kan gegevens- of rekenintensief zijn. Batchjobs kunnen volgens een vooraf bepaald schema worden uitgevoerd of op verzoek worden gestart. En omdat batch jobs meestal langlopende jobs zijn, zijn constante controles en het herstarten na een bepaalde fout gemeenschappelijke kenmerken van batch jobs.

1.1 Geschiedenis van Java Batch Processing

Batch processing voor Java Platform werd geïntroduceerd als onderdeel van JSR 352 specificatie, onderdeel van het Java EE 7 platform, definieert het programmeermodel voor batch applicaties plus een runtime om batch jobs uit te voeren en te beheren.

1.2 Architectuur van Java Batch

Onderstaand diagram toont de basiscomponenten voor batch processing.

Architectuur voor Java Batch Processing

De architectuur voor batch-toepassingen lost problemen met batch-verwerking op, zoals jobs, steps, repositories, reader processor writer patterns, chunks, checkpoints, parallelle verwerking, flow, retries, sequencing, partitionering, enz.

Laten we de stroom van de architectuur begrijpen.

  • Job repository bevat de jobs die moeten worden uitgevoerd.
  • JobLauncher haalt een job uit Job repository.
  • Elke job bevat stappen. De stappen zijn ItemReader, ItemProcessor en ItemWriter.
  • Item Reader is degene die de gegevens leest.
  • Item Process is degene die de gegevens zal verwerken op basis van business logica.
  • De Item schrijver zal de gegevens terugschrijven naar de gedefinieerde bron.

1.3 Batch Processing Componenten.

We zullen nu proberen om de batch processing componenten in detail te begrijpen.

  • Job: Een job omvat het gehele batchproces. Het bevat een of meer stappen. Een job wordt samengesteld met behulp van een Job Specification Language (JSL) waarin de volgorde wordt gespecificeerd waarin de stappen moeten worden uitgevoerd. In JSR 352 wordt JSL gespecificeerd in een XML-bestand dat bekend staat als het Job XML-bestand. Een job is in feite een container met stappen.
  • Step: Een stap is een domeinobject dat een onafhankelijke, sequentiële fase van de job bevat. Een stap bevat alle noodzakelijke logica en gegevens om de eigenlijke verwerking uit te voeren. De definitie van een stap is volgens de batch-specificatie vaag gehouden omdat de inhoud van een stap zuiver toepassingsspecifiek is en zo complex of eenvoudig kan zijn als de ontwikkelaar wil. Er zijn twee soorten stappen: chunk en taak georiënteerd.
  • Job Operator: Het biedt een interface voor het beheer van alle aspecten van de verwerking van jobs, waaronder operationele commando’s, zoals starten, herstarten en stoppen, evenals job repository commando’s, zoals het ophalen van job- en step-uitvoeringen.
  • Job Repository: Deze bevat informatie over momenteel lopende jobs en historische gegevens over de job. JobOperator biedt API’s om toegang te krijgen tot deze repository. Een JobRepository kan worden geïmplementeerd met behulp van, een database of een bestandssysteem.

De volgende sectie zal helpen bij het begrijpen van een aantal veel voorkomende tekens van een batch architectuur.

1.3 Stappen in Job

Een Stap is een onafhankelijke fase van een Job. Zoals hierboven besproken, zijn er twee soorten stappen in een Job. We zullen beide typen hieronder in detail proberen te begrijpen.

1.3.1 Chunk-georiënteerde stappen

Chunk-stappen lezen en verwerken één item tegelijk en groeperen de resultaten in een chunk. De resultaten worden dan opgeslagen wanneer de chunk een vooraf gedefinieerde grootte heeft bereikt. Chunk-georiënteerde verwerking maakt het opslaan van resultaten efficiënter wanneer de gegevensverzameling enorm is. Het bestaat uit drie delen.

  • De item lezer leest de input een voor een uit een gegevensbron die een database, flat file, log file, enz. kan zijn.
  • De processor zal de gegevens een voor een verwerken op basis van de gedefinieerde business logic.
  • Een schrijver schrijft de gegevens in brokken. De grootte van de chunk is voorgedefinieerd en is configureerbaar

Als onderdeel van chunk-stappen zijn er checkpoints die het raamwerk informatie verschaffen voor de voltooiing van chunks. Als er een fout optreedt tijdens de verwerking van een chunk, kan het proces opnieuw worden gestart op basis van het laatste checkpoint.

1.3.2 Task-Oriented Steps

Het voert andere taken uit dan het verwerken van items uit een gegevensbron. Daartoe behoren het maken of verwijderen van mappen, het verplaatsen van bestanden, het maken of verwijderen van databasetabellen, enz. Taakstappen zijn meestal niet langlopend in vergelijking met chunk-stappen.

In een normaal scenario worden taakgerichte stappen gebruikt na chunk-georiënteerde stappen waar er een opschoning nodig is. Bijvoorbeeld, we krijgen logbestanden als uitvoer van een toepassing. De chunk-stappen worden gebruikt om de gegevens te verwerken en zinvolle informatie uit de log-bestanden te halen.

De taak-stap wordt dan gebruikt om oudere log-bestanden op te schonen die niet meer nodig zijn.

1.3.3 Parallelle verwerking

Batch-jobs voeren vaak dure rekenkundige bewerkingen uit en verwerken grote hoeveelheden gegevens. Batch-toepassingen kunnen profiteren van parallelle verwerking in twee scenario’s.

  • Stappen die onafhankelijk van elkaar van aard zijn, kunnen op verschillende threads worden uitgevoerd.
  • Chunk-georiënteerde stappen waarbij de verwerking van elk item onafhankelijk is van de resultaten van de verwerking van eerdere items, kunnen op meer dan één thread worden uitgevoerd.

Batch processing helpt om taken af te maken en bewerkingen sneller uit te voeren voor enorme data.

Tools and Technologies

Laten we eens kijken naar de technologieën en tool gebruikt voor het bouwen van het programma.

  • Eclipse Oxygen.2 Release (4.7.2)
  • Java – versie 9.0.4
  • Gradle- 4.3
  • Spring boot – 2.0.1-Release
  • HSQL Database

Project Structuur

De project structuur zal eruit zien zoals weergegeven in de afbeelding hieronder.

Project Structuur voor Java Batch

De bovenstaande project structuur is met behulp van Gradle. Dit project kan ook worden gemaakt met maven en de build.gralde zal worden vervangen door pom.xml bestand. De structuur van het project zal iets verschuiven met het gebruik van Maven voor de build.

Een doel van het programma

Als onderdeel van het programma, zullen we proberen om een eenvoudige java batch applicatie met behulp van de lente boot te maken. Deze applicatie zal de volgende taken uitvoeren.

  1. Lezen: – Lees werknemer gegevens uit een CSV-bestand.
  2. Verwerk de gegevens: – Zet de werknemersgegevens om in allemaal hoofdletters.
  3. Schrijven: – Schrijf de verwerkte werknemersgegevens terug in de database.

4.1 Gradle build

We gebruiken Gradle voor de build als onderdeel van het programma. Het build.gradle bestand ziet er uit zoals hieronder getoond.

build.gradle

buildscript { repositories { mavenCentral() } dependencies { classpath("org.springframework.boot:spring-boot-gradle-plugin:2.0.1.RELEASE") }}apply plugin: 'java'apply plugin: 'eclipse'apply plugin: 'idea'apply plugin: 'org.springframework.boot'apply plugin: 'io.spring.dependency-management'bootJar { baseName = 'java-batch' version = '1.0'}repositories { mavenCentral()}sourceCompatibility = 1.8targetCompatibility = 1.8dependencies { compile("org.springframework.boot:spring-boot-starter-batch") compile("org.hsqldb:hsqldb") testCompile("junit:junit")}

In het bovenstaande build.gradle bestand vertelt apply plugin: 'java' ons de plugin die moet worden ingesteld. Voor ons is dat Java plugin.
repositories{} laat ons weten uit welke repository de dependency moet worden opgehaald. Wij hebben mavenCentral gekozen om de jars van de dependency te halen. We kunnen jcenter ook gebruiken voor het ophalen van de betreffende dependency jars.

dependencies {} tag wordt gebruikt om de nodige jar file details op te geven die voor het project opgehaald moeten worden. apply plugin: 'org.springframework.boot' deze plugin wordt gebruikt voor het specificeren van een spring-boot project. boot jar{} specificeert de eigenschappen van de jar die zal worden gegenereerd uit de build.

4.2 Voorbeeld data file

Om gegevens te verstrekken voor de read fase, zullen we gebruik maken van een CSV-bestand met werknemer gegevens.

Het bestand zal eruit zien als hieronder.

Sample CSV file

John,FosterJoe,ToyJustin,TaylorJane,ClarkJohn,Steve

Het voorbeeld data bestand bevat de voor-en achternaam van de werknemer. We zullen dezelfde gegevens gebruiken om te verwerken en vervolgens in de database in te voegen.

4.3 SQL scripts

We gebruiken HSQL database die een geheugen gebaseerde database is. Het script ziet er uit zoals hieronder getoond.

SQL script

DROP TABLE employee IF EXISTS;CREATE TABLE employee ( person_id BIGINT IDENTITY NOT NULL PRIMARY KEY, first_name VARCHAR(20), last_name VARCHAR(20));

Spring Boot draait schema-@@platform@@.sql automatisch wanneer het opstart. -all is de standaard voor alle platforms. Dus de tabel creatie zal vanzelf gebeuren wanneer de applicatie start en het zal beschikbaar zijn totdat de applicatie is opgestart.

4.4 Model Class

We gaan een Employee.java class maken als de model class. De klasse ziet er uit als hieronder.

Model klasse voor het programma

package com.batch;public class Employee { private String lastName; private String firstName; public Employee() { } public Employee(String firstName, String lastName) { this.firstName = firstName; this.lastName = lastName; } public void setFirstName(String firstName) { this.firstName = firstName; } public String getFirstName() { return firstName; } public String getLastName() { return lastName; } public void setLastName(String lastName) { this.lastName = lastName; } @Override public String toString() { return "firstName: " + firstName + ", lastName: " + lastName; }}

@Override wordt gebruikt voor het overschrijven van de standaard implementatie van de toString() methode.

4.5 Configuratie klasse

We gaan een BatchConfiguration.java klasse maken die de configuratie klasse zal zijn voor batch processing. Het java-bestand zal er uitzien zoals hieronder getoond.

BatchConfiguration.java

package com.batch.config;import javax.sql.DataSource;import org.springframework.batch.core.Job;import org.springframework.batch.core.JobExecutionListener;import org.springframework.batch.core.Step;import org.springframework.batch.core.configuration.annotation.EnableBatchProcessing;import org.springframework.batch.core.configuration.annotation.JobBuilderFactory;import org.springframework.batch.core.configuration.annotation.StepBuilderFactory;import org.springframework.batch.core.launch.support.RunIdIncrementer;import org.springframework.batch.item.database.BeanPropertyItemSqlParameterSourceProvider;import org.springframework.batch.item.database.JdbcBatchItemWriter;import org.springframework.batch.item.database.builder.JdbcBatchItemWriterBuilder;import org.springframework.batch.item.file.FlatFileItemReader;import org.springframework.batch.item.file.builder.FlatFileItemReaderBuilder;import org.springframework.batch.item.file.mapping.BeanWrapperFieldSetMapper;import org.springframework.batch.item.file.mapping.DefaultLineMapper;import org.springframework.batch.item.file.transform.DelimitedLineTokenizer;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.context.annotation.Bean;import org.springframework.context.annotation.Configuration;import org.springframework.core.io.ClassPathResource;import org.springframework.jdbc.core.JdbcTemplate;import com.batch.Employee;import com.batch.processor.EmployeeItemProcessor;@Configuration@EnableBatchProcessingpublic class BatchConfiguration { @Autowired public JobBuilderFactory jobBuilderFactory; @Autowired public StepBuilderFactory stepBuilderFactory; // tag::readerwriterprocessor @Bean public FlatFileItemReader reader() { return new FlatFileItemReaderBuilder() .name("EmployeeItemReader") .resource(new ClassPathResource("sample-data.csv")) .delimited() .names(new String{"firstName", "lastName"}) .fieldSetMapper(new BeanWrapperFieldSetMapper() {{ setTargetType(Employee.class); }}) .build(); } @Bean public EmployeeItemProcessor processor() { return new EmployeeItemProcessor(); } @Bean public JdbcBatchItemWriter writer(DataSource dataSource) { return new JdbcBatchItemWriterBuilder() .itemSqlParameterSourceProvider(new BeanPropertyItemSqlParameterSourceProvider<>()) .sql("INSERT INTO employee (first_name, last_name) VALUES (:firstName, :lastName)") .dataSource(dataSource) .build(); } // end::readerwriterprocessor // tag::jobstep @Bean public Job importUserJob(JobCompletionNotificationListener listener, Step step1) { return jobBuilderFactory.get("importUserJob") .incrementer(new RunIdIncrementer()) .listener(listener) .flow(step1) .end() .build(); } @Bean public Step step1(JdbcBatchItemWriter writer) { return stepBuilderFactory.get("step1") .<Employee, Employee> chunk(10) .reader(reader()) .processor(processor()) .writer(writer) .build(); } // end::jobstep}

@EnableBatchProcessing annotatie wordt gebruikt voor het inschakelen van batchverwerking.
JobBuilderFactory is de fabriek die wordt gebruikt voor het bouwen van een job.
StepBuilderFactory wordt gebruikt voor het maken van stappen.
De methode step1() heeft een eigenschap chunk(). Dit is de eigenschap die wordt gebruikt voor het opdelen van de invoer in een gedefinieerde grootte. Voor ons is de grootte 10.

4.6 Item Processor

Item processor is een interface die verantwoordelijk zal zijn voor het verwerken van de gegevens. We zullen de interface in EmployeeItemProcessor.java implementeren. De java klasse zal er uitzien zoals hieronder getoond.

EmployeeItemProcessor.java

package com.batch.processor;import org.slf4j.Logger;import org.slf4j.LoggerFactory;import org.springframework.batch.item.ItemProcessor;import com.batch.Employee;public class EmployeeItemProcessor implements ItemProcessor<Employee, Employee> { private static final Logger log = LoggerFactory.getLogger(EmployeeItemProcessor.class); @Override public Employee process(Employee emp) throws Exception { final String firstName = emp.getFirstName().toUpperCase(); final String lastName = emp.getLastName().toUpperCase(); final Employee transformedEmployee = new Employee(firstName, lastName); log.info("Converting (" + emp + ") into (" + transformedEmployee + ")"); return transformedEmployee; }}

In de process() methode zullen we de gegevens ophalen en we zullen ze omzetten in de hoofdletternaam.

4.7 JobExecutionSupportListener class

JobExecutionListenerSupport is de interface die zal verwittigen wanneer de job voltooid is. Als onderdeel van de interface, hebben we afterJob methode. Deze methode wordt gebruikt om de voltooiing van de job te melden.

JobCompletionNotificationListener.java

package com.batch.config;import java.util.List;import org.slf4j.Logger;import org.slf4j.LoggerFactory;import org.springframework.batch.core.BatchStatus;import org.springframework.batch.core.JobExecution;import org.springframework.batch.core.listener.JobExecutionListenerSupport;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.jdbc.core.JdbcTemplate;import org.springframework.jdbc.core.RowMapper;import org.springframework.stereotype.Component;import com.batch.Employee;@Componentpublic class JobCompletionNotificationListener extends JobExecutionListenerSupport {private static final Logger log = LoggerFactory.getLogger(JobCompletionNotificationListener.class);private final JdbcTemplate jdbcTemplate;@Autowiredpublic JobCompletionNotificationListener(JdbcTemplate jdbcTemplate) {this.jdbcTemplate = jdbcTemplate;}@Overridepublic void afterJob(JobExecution jobExecution) {RowMapper rowMapper = (rs, rowNum) -> {Employee e = new Employee();e.setFirstName(rs.getString(1));e.setLastName(rs.getString(2));return e;};if(jobExecution.getStatus() == BatchStatus.COMPLETED) {log.info("!!! JOB FINISHED! Time to verify the results");List empList= jdbcTemplate.query("SELECT first_name, last_name FROM employee",rowMapper);log.info("Size of List "+empList.size());for (Employee emp: empList) {log.info("Found: "+emp.getFirstName()+" "+emp.getLastName());}}}}

In deze methode halen we de gegevens uit de database na voltooiing van de job en drukken we het resultaat af op de console om de verwerking van de gegevens te controleren.

4.8 Application class

We zullen een application class maken die de hoofdmethode zal bevatten die verantwoordelijk is voor het starten van het java batch programma. De klasse ziet er uit zoals hieronder getoond.

Application.java

package com.batch;import org.springframework.boot.SpringApplication;import org.springframework.boot.autoconfigure.SpringBootApplication;@SpringBootApplicationpublic class Application { public static void main(String args) throws Exception { SpringApplication.run(Application.class, args); }}

@SpringBootApplication is de annotatie die gebruikt wordt om een programma als een spring boot programma te specificeren.

Output

Laten we de applicatie als een Java applicatie uitvoeren. We krijgen de volgende uitvoer op de console.

De uitvoer van JavaBatch programma

De workflow van het batch programma is heel duidelijk te zien in de uitvoer. De Job begint met importUserJob, dan stap-1 uitvoering begint waar het zet de gelezen gegevens in hoofdletters.

Na verwerking van stap, kunnen we het hoofdletters resultaat te zien op de console.

Samenvatting

In deze tutorial, leerden we de volgende dingen:

  1. Java batch bevat Jobs die meerdere stappen kan bevatten.
  2. Elke stap is een combinatie van lezen, verwerken, schrijven.
  3. We kunnen de gegevens in verschillende grootte voor processing.

7. Download het Eclipse-project

Dit was een tutorial voor JavaBatch met SpringBoot.