I dagens verden har internettet ændret den måde, vi lever vores liv på, og en af de vigtigste grunde til det er brugen af internettet til de fleste af de daglige gøremål. Dette har ført til store mængder data, der er tilgængelige til behandling.
Som nogle af de eksempler, hvor der er tale om store mængder data, kan nævnes behandling af lønsedler, kontoudtog, renteberegning osv. Så forestil dig, at hvis alle disse opgaver skulle udføres manuelt, ville det tage evigheder at afslutte disse opgaver.
Hvordan gøres det i den nuværende tidsalder? Svaret er batchbehandling.
- Indledning
- 1.1 Historik for Java Batch Processing
- 1.2. Arkitektur for Java Batch
- 1.3 Batch Processing Components.
- 1.3 Trin i job
- 1.3.3.1 Chunk-orienterede trin
- 1.3.3.2 Opgaveorienterede trin
- 1.3.3.3 Parallel behandling
- Værktøjer og teknologier
- Projektstruktur
- Et mål med programmet
- 4.1 Gradle build
- 4.2 Eksempel på datafil
- 4.3 SQL-scripts
- 4.4 Modelklasse
- 4.5 Konfigurationsklasse
- 4.6 Item Processor
- 4.7 JobExecutionSupportListener-klassen
- 4.8 Applikationsklasse
- Output
- Summary
- 7. Download Eclipse-projektet
Indledning
Batchbehandling udføres på bulkdata, uden manuel indgriben, og langvarig. Det kan være data- eller beregningsintensivt. Batchjobs kan køres efter en foruddefineret tidsplan eller kan iværksættes efter behov. Da batchjobs normalt er langtidsjobs, er konstante kontroller og genstart efter en vis fejl også almindelige funktioner, der findes i batchjobs.
1.1 Historik for Java Batch Processing
Batch processing for Java Platform blev introduceret som en del af JSR 352-specifikationen, der er en del af Java EE 7-platformen, definerer programmeringsmodellen for batch-applikationer plus en runtime til at køre og administrere batchjobs.
1.2. Arkitektur for Java Batch
Nedenstående diagram viser de grundlæggende komponenter til batchbehandling.
Arkitektur for Java Batch Processing
Arkitekturen for batch-applikationer løser batchbehandlingsproblemer som jobs, trin, repositories, reader processor writer-mønstre, chunks, checkpoints, parallel behandling, flow, retries, sequencing, partitionering osv.
Lad os forstå arkitekturens flow.
- Job repository indeholder de job, der skal køres.
-
JobLauncher
trækker et job ud fra Job repository. - Et hvert job indeholder trin. Trinene er
ItemReader
,ItemProcessor
ogItemWriter
. - Item Reader er den, der læser dataene.
- Item Process er den, der vil behandle dataene baseret på forretningslogik.
- Element writer vil skrive dataene tilbage til den definerede kilde.
1.3 Batch Processing Components.
Vi vil nu forsøge at forstå batchbehandlingskomponenterne i detaljer.
- Job: Et job omfatter hele batchprocessen. Det indeholder et eller flere trin. Et job sammensættes ved hjælp af et jobspecifikationssprog (Job Specification Language (JSL)), der angiver den rækkefølge, i hvilken trinene skal udføres. I JSR 352 specificeres JSL i en XML-fil, den såkaldte job XML-fil. Et job er grundlæggende en container, der indeholder trin.
- Trin: Et trin er et domæneobjekt, der indeholder en uafhængig, sekventiel fase af jobbet. Et trin indeholder al den nødvendige logik og alle de data, der er nødvendige for at udføre den faktiske behandling. Definitionen af et trin holdes vag i henhold til batch-specifikationen, fordi indholdet af et trin er rent applikationsspecifikt og kan være lige så komplekst eller simpelt, som udvikleren ønsker. Der findes to slags trin: chunk- og opgaveorienterede.
- Job Operator: Det giver en grænseflade til håndtering af alle aspekter af jobbehandling, hvilket omfatter operationelle kommandoer, såsom start, genstart og stop, samt kommandoer til jobrepositoriet, såsom hentning af job- og trinudførelser.
- Job Repository: Det indeholder oplysninger om job, der kører i øjeblikket, og historiske data om jobbet.
JobOperator
giver API’er til at få adgang til dette repository. EtJobRepository
kan implementeres ved hjælp af, en database eller et filsystem.
Det følgende afsnit vil hjælpe med at forstå nogle almindelige karakterer i en batch-arkitektur.
1.3 Trin i job
Et trin er en uafhængig fase af et job. Som diskuteret ovenfor er der to typer trin i et Job. Vi vil forsøge at forstå begge typer i detaljer nedenfor.
1.3.3.1 Chunk-orienterede trin
Chunk-trin vil læse og behandle et element ad gangen og gruppere resultaterne i et chunk. Resultaterne gemmes derefter, når chunken når en foruddefineret størrelse. Chunk-orienteret behandling gør lagring af resultater mere effektiv, når datasættet er stort. Den indeholder tre dele.
- Elementlæseren læser input den ene efter den anden fra en datakilde, som kan være en database, flad fil, logfil osv.
- Processoren behandler dataene en efter en på baggrund af den definerede forretningslogik.
- En writer skriver dataene i chunks. Størrelsen af chunken er foruddefineret og kan konfigureres
Som en del af chunk-trinnene er der checkpoints, der giver oplysninger til rammen om færdiggørelsen af chunks. Hvis der opstår en fejl under en chunk-behandling, kan processen genstartes baseret på det sidste kontrolpunkt.
1.3.3.2 Opgaveorienterede trin
Det udfører andre opgaver end behandling af elementer fra en datakilde. Hvilket omfatter oprettelse eller fjernelse af mapper, flytning af filer, oprettelse eller sletning af databasetabeller osv. Opgaveorienterede trin er normalt ikke langvarige i forhold til chunk-trin.
I et normalt scenarie anvendes opgaveorienterede trin efter chunk-orienterede trin, hvor der er behov for oprydning. Vi får f.eks. logfiler som et output fra et program. De chunk-orienterede trin bruges til at behandle dataene og få meningsfulde oplysninger ud af logfilerne.
Det opgaveorienterede trin bruges derefter til at rydde op i ældre logfiler, som der ikke længere er brug for.
1.3.3.3 Parallel behandling
Batchjobs udfører ofte dyre beregningsoperationer og behandler store mængder af data. Batch-applikationer kan drage fordel af parallelbehandling i to scenarier.
- Stræk, der er uafhængige i deres natur, kan køre på forskellige tråde.
- Chunk-orienterede trin, hvor behandlingen af hvert element er uafhængig af resultaterne af behandlingen af tidligere elementer, kan køre på mere end én tråd.
Batchbehandling hjælper med at afslutte opgaver og udføre operationer hurtigere for store data.
Værktøjer og teknologier
Lad os se på de teknologier og det værktøj, der anvendes til opbygning af programmet.
- Eclipse Oxygen.2 Release (4.7.2)
- Java – version 9.0.4
- Gradle- 4.3
- Spring boot – 2.0.1-Release
- HSQL Database
Projektstruktur
Projektstrukturen vil se ud som vist i billedet nedenfor.
Projektstruktur for Java Batch
Den ovenstående projektstruktur bruger Gradle. Dette projekt kan også oprettes ved hjælp af maven, og build.gralde vil blive erstattet med pom.xml-filen. Strukturen af projektet vil udskyde lidt med brugen af Maven til build.
Et mål med programmet
Som en del af programmet vil vi forsøge at oprette en simpel java batch applikation ved hjælp af spring boot. Denne applikation vil udføre følgende opgaver.
- Læs: – Læs medarbejderdata fra en CSV-fil.
- Behandl dataene: – Konverter medarbejderdataene til alle store bogstaver.
- Skriv: – Skriv de behandlede medarbejderdata tilbage i databasen.
4.1 Gradle build
Vi bruger Gradle til build’et som en del af programmet. build.gradle
-filen vil se ud som vist nedenfor.
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")}
I ovenstående build.gradle
-fil fortæller apply plugin: 'java'
os det plugin, der skal indstilles. For os er det Java-plugin.repositories{}
oplyser os om det repository, som afhængigheden skal hentes fra. Vi har valgt mavenCentral
til at trække afhængighedens jars. Vi kan også bruge jcenter
til at trække de respektive afhængighedsjars.
dependencies {}
-tag bruges til at angive de nødvendige jar-filoplysninger, der skal trækkes for projektet. apply plugin: 'org.springframework.boot'
dette plugin bruges til at angive et spring-boot-projekt. boot jar{}
vil angive egenskaberne for den jar, der vil blive genereret fra buildet.
4.2 Eksempel på datafil
For at levere data til læsefasen vil vi bruge en CSV-fil, der indeholder medarbejderdata.
Filen vil se ud som vist nedenfor.
Eksempel på CSV-fil
John,FosterJoe,ToyJustin,TaylorJane,ClarkJohn,Steve
Eksempel på datafil indeholder for- og efternavn på medarbejderen. Vi vil bruge de samme data til behandling og derefter indsættelse i databasen.
4.3 SQL-scripts
Vi bruger HSQL-database, som er en hukommelsesbaseret database. Scriptet vil se ud som vist nedenfor.
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 kører schema-@@platform@@.sql
automatisk, når den starter. -all
er standard for alle platforme. Så tabeloprettelsen sker af sig selv, når programmet starter, og den vil være tilgængelig, indtil programmet er oppe at køre.
4.4 Modelklasse
Vi opretter en Employee.java
-klasse som modelklasse. Klassen vil se ud som vist nedenfor.
Modelklasse for programmet
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
bruges til at overskrive standardimplementeringen af toString()
-metoden.
4.5 Konfigurationsklasse
Vi vil oprette en BatchConfiguration.java
-klasse, som vil være konfigurationsklassen for batchbehandling. Javafilen vil se ud som vist nedenfor.
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
-annotationen bruges til at aktivere batchbehandling.JobBuilderFactory
er fabrikken, som bruges til at opbygge et job.StepBuilderFactory
bruges til trinoprettelse.
Metoden step1()
har en egenskab chunk()
. Dette er den egenskab, der bruges til at opdele input i en defineret størrelse. For os er størrelsen 10.
4.6 Item Processor
Itemprocessor er en grænseflade, som vil være ansvarlig for behandlingen af dataene. Vi vil implementere grænsefladen i EmployeeItemProcessor.java
. Java-klassen vil se ud som vist nedenfor.
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; }}
I process()
-metoden henter vi dataene, og vi vil omdanne dem til et stort navn.
4.7 JobExecutionSupportListener-klassen
JobExecutionListenerSupport
er den grænseflade, der giver besked, når jobbet er afsluttet. Som en del af grænsefladen har vi afterJob
metode. Denne metode bruges til at bogføre afslutningen af jobbet.
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());}}}}
I denne metode henter vi dataene fra databasen efter afslutningen af jobbet, og vi udskriver resultatet på konsollen for at verificere den behandling, der blev udført på dataene.
4.8 Applikationsklasse
Vi vil oprette en applikationsklasse, som vil indeholde den hovedmetode, der er ansvarlig for at udløse java-batchprogrammet. Klassen vil se ud som vist nedenfor.
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
er den annotation, der bruges til at angive et program som et spring boot-program.
Output
Lad os udføre programmet som et java-program. Vi får følgende output på konsollen.
Output af JavaBatch-program
Arbejdsgangen i batchprogrammet er meget tydeligt tilgængelig i output. Jobbet starter med importUserJob
, derefter starter udførelsen af trin-1, hvor det konverterer de læste data til store bogstaver.
Efter behandlingen af trin kan vi se resultatet med store bogstaver på konsollen.
Summary
I denne tutorial har vi lært følgende ting:
- Java batch indeholder Jobs, som kan indeholde flere trin.
- Hvert trin er en kombination af læsning, behandling og skrivning.
- Vi kan dele dataene op i forskellige størrelser til behandling.
7. Download Eclipse-projektet
Dette var en tutorial for JavaBatch med SpringBoot.