Spring Batch pomoću particionera

1. Pregled

U našem prethodnom uvodu u Spring Batch uveli smo okvir kao alat za skupnu obradu. Također smo istražili detalje konfiguracije i implementaciju za izvršavanje zadatka s jednim navojem i jednim procesom.

Za provedbu posla s nekom paralelnom obradom pruža se niz mogućnosti. Na višoj razini postoje dva načina paralelne obrade:

  1. Jednoprocesni, višenitni
  2. Višeprocesni

U ovom ćemo kratkom članku raspraviti o podjeli Korak, koji se može implementirati i za pojedinačne i za višeprocesne poslove.

2. Dijeljenje koraka

Spring Batch s particioniranjem pruža nam mogućnost da podijelimo izvršavanje a Korak:

Pregled particioniranja

Gornja slika prikazuje provedbu a Posao s pregrađenim Korak.

Tamo je Korak pod nazivom "Master", čije je izvršenje podijeljeno u neke "slave" korake. Ti robovi mogu zamijeniti gospodara, a ishod će i dalje biti nepromijenjen. I master i slave su slučajevi Korak. Podređeni uređaji mogu biti udaljene usluge ili samo lokalno izvršavanje niti.

Ako je potrebno, možemo prenijeti podatke od master-a do slave-a. Meta podaci (tj. Spremište poslova), osigurava da se svaki slave izvrši samo jednom u jednom izvršenju datoteke Posao.

Evo dijagrama redoslijeda koji pokazuje kako sve to funkcionira:

Korak podjele

Kao što je prikazano, Korak koraka vozi pogubljenje. The Rukovač particijama odgovoran je za razdvajanje djela "Gospodara" na "Robove". Desno Korak je rob.

3. Maven POM

Ovisnosti o Mavenu iste su kao što je spomenuto u našem prethodnom članku. Odnosno, Spring Core, Spring Batch i ovisnost baze podataka (u našem slučaju, SQLite).

4. Konfiguracija

U našem uvodnom članku vidjeli smo primjer pretvorbe nekih financijskih podataka iz CSV u XML datoteku. Proširimo isti primjer.

Ovdje ćemo pretvoriti financijske podatke iz 5 CSV datoteka u odgovarajuće XML datoteke, koristeći implementaciju s više niti.

To možemo postići pomoću jednog Posao i Korak pregrađivanje. Imat ćemo pet niti, po jednu za svaku CSV datoteku.

Prije svega, kreirajmo posao:

@Bean (name = "partitionerJob") javni posao partitionerJob () baca UnexpectedInputException, MalformedURLException, ParseException {return jobs.get ("partitioningJob") .start (partitionStep ()) .build (); }

Kao što vidimo, ovo Posao započinje s Korak koraka. Ovo je naš glavni korak koji će biti podijeljen u različite slave korake:

@Bean public Step partitionStep () baca UnexpectedInputException, MalformedURLException, ParseException {return steps.get ("partitionStep") .partitioner ("slaveStep", partitioner ()) .step (slaveStep ()) .taskExecutor (taskExecutor). (); }

Ovdje ćemo stvoriti Korak particioniranja pomoću StepBuilderFactory. Za to trebamo dati podatke o SlaveSteps i Pregradni zid.

The Pregradni zid je sučelje koje pruža mogućnost definiranja skupa ulaznih vrijednosti za svakog od pomoćnih uređaja. Drugim riječima, ovdje ide logika za podjelu zadataka u odgovarajuće niti.

Stvorimo njegovu implementaciju, tzv CustomMultiResourcePartitioner, gdje ćemo staviti ulaznu i izlaznu datoteku u ExecutionContext da se proslijedi na svaki slave korak:

javna klasa CustomMultiResourcePartitioner implementira Partitioner {@Override javna particija karte (int gridSize) {Map map = new HashMap (gridSize); int i = 0, k = 1; za (Resurs resursa: resursi) {ExecutionContext context = new ExecutionContext (); Assert.state (resource.exists (), "Resurs ne postoji:" + resurs); context.putString (keyName, resource.getFilename ()); context.putString ("opFileName", "output" + k +++ ". xml"); map.put (PARTITION_KEY + i, kontekst); i ++; } karta povratka; }}

Također ćemo stvoriti grah za ovu klasu, gdje ćemo dati izvorni direktorij za ulazne datoteke:

@Bean javni CustomMultiResourcePartitioner partitioner () {CustomMultiResourcePartitioner partitioner = novi CustomMultiResourcePartitioner (); Resurs [] resursi; isprobajte {resources = resursePatternResolver .getResources ("datoteka: src / main / resources / input / *. csv"); } catch (IOException e) {throw new RuntimeException ("I / O problemi pri rješavanju" + "obrazac ulazne datoteke.", e); } partitioner.setResources (resursi); vratiti particiju; }

Definirat ćemo korak slave, kao i bilo koji drugi korak kod čitača i pisca. Čitač i pisač bit će isti kao što smo vidjeli u našem uvodnom primjeru, osim što će parametar datoteke dobiti od datoteke StepExecutionContext.

Imajte na umu da ovaj grah treba postepeno obuhvatiti kako bi mogao primiti stepExecutionContext parametara, na svakom koraku. Ako ne bi trebali biti opsežni, njihov će se grah inicijalno stvoriti i neće prihvatiti imena datoteka na razini koraka:

@StepScope @Bean public FlatFileItemReader itemReader (@Value ("# {stepExecutionContext [fileName]}") Naziv datoteke niza) baca UnexpectedInputException, ParseException {FlatFileItemReader čitač = novi FlatFileItemReader (); DelimitedLineTokenizer tokenizer = novi DelimitedLineTokenizer (); Niz [] tokeni = {"korisničko ime", "userid", "transactiondate", "iznos"}; tokenizer.setNames (tokeni); reader.setResource (novi ClassPathResource ("input /" + naziv datoteke)); DefaultLineMapper lineMapper = novi DefaultLineMapper (); lineMapper.setLineTokenizer (tokenizer); lineMapper.setFieldSetMapper (novi RecordFieldSetMapper ()); reader.setLinesToSkip (1); reader.setLineMapper (lineMapper); povratni čitač; } 
@Bean @StepScope public ItemWriter itemWriter (Marshaller marshaller, @Value ("# {stepExecutionContext [opFileName]}") String filename) baca MalformedURLException {StaxEventItemWriter itemWriter = new StaxEventItemWriter (New StaxEventItemWriter) itemWriter.setMarshaller (marshaller); itemWriter.setRootTagName ("actionRecord "); itemWriter.setResource (novi ClassPathResource ("xml /" + naziv datoteke)); vratiti itemWriter; }

Dok spominjemo čitač i pisac u slave koraku, argumente možemo proslijediti kao nule jer se ta imena datoteka neće koristiti jer će imena datoteka primiti iz stepExecutionContext:

@Bean public Step slaveStep () baca UnexpectedInputException, MalformedURLException, ParseException {return steps.get ("slaveStep"). Chunk (1) .reader (itemReader (null)) .writer (itemWriter (marshaller (), null)). (); }

5. Zaključak

U ovom vodiču razgovarali smo o tome kako implementirati posao s paralelnom obradom pomoću Spring Batch-a.

Kao i uvijek, kompletna implementacija za ovaj primjer dostupna je na GitHubu.