Výkon rámcov mapovania Java

1. Úvod

Vytváranie veľkých aplikácií Java zložených z viacerých vrstiev si vyžaduje použitie viacerých modelov, ako je napríklad model vytrvalosti, doménový model alebo takzvané DTO. Používanie viacerých modelov pre rôzne aplikačné vrstvy bude vyžadovať, aby sme poskytli spôsob mapovania medzi fazuľami.

Ak to urobíte manuálne, môžete rýchlo vytvoriť veľa štandardných kódov a stráviť veľa času. Našťastie pre nás existuje viac rámcov na mapovanie objektov pre Javu.

V tomto výučbe budeme porovnávať výkon najpopulárnejších rámcov mapovania Java.

2. Mapovacie rámce

2.1. Buldozér

Dozer je mapovací rámec, ktorý využíva rekurziu na kopírovanie údajov z jedného objektu do druhého. Rámec je schopný nielen kopírovať vlastnosti medzi fazuľami, ale dokáže aj automaticky prevádzať medzi rôznymi typmi.

Aby sme mohli použiť rámec Dozer, musíme do nášho projektu pridať takúto závislosť:

 com.github.dozermapper dozer-core 6.5.0 

Viac informácií o použití rámca Dozer nájdete v tomto článku.

Dokumentáciu k rámcu nájdete tu.

2.2. Orika

Orika je rámec mapovania fazule na fazuľu, ktorý rekurzívne kopíruje údaje z jedného objektu do druhého.

Všeobecný princíp práce Oriky je podobný ako u Dozera. Hlavným rozdielom medzi nimi je skutočnosť, že Orika používa generovanie bytecode. To umožňuje generovanie rýchlejších mapovačov s minimálnou réžiou.

Ak to chcete použiť,musíme do nášho projektu pridať takúto závislosť:

 ma.glasnost.orika orika-core 1.5.4 

Podrobnejšie informácie o používaní Oriky nájdete v tomto článku.

Aktuálnu dokumentáciu k rámcu nájdete tu.

2.3. MapStruct

MapStruct je generátor kódu, ktorý automaticky generuje triedy mapovačov fazule.

MapStruct má tiež schopnosť prevádzať medzi rôznymi dátovými typmi. Viac informácií o tom, ako ju používať, nájdete v tomto článku.

Ak chcete pridať MapStructdo nášho projektu musíme zahrnúť nasledujúcu závislosť:

 org.mapstruct mapstruct 1.3.1.Final 

Dokumentáciu k rámcu nájdete tu.

2.4. ModelMapper

ModelMapper je rámec, ktorého cieľom je zjednodušiť mapovanie objektov určením spôsobu vzájomného mapovania objektov na základe konvencií. Poskytuje typovo bezpečné a refaktoringovo bezpečné API.

Viac informácií o rámci sa nachádza v dokumentácii.

Ak chcete zahrnúť ModelMapper do nášho projektu, musíme pridať nasledujúcu závislosť:

 org.modelmapper modelmapper 2.3.8 

2.5. JMapper

JMapper je mapovací rámec, ktorého cieľom je poskytnúť ľahko použiteľné a vysoko výkonné mapovanie medzi Java Beans.

Rámec sa zameriava na uplatnenie princípu DRY pomocou anotácií a relačného mapovania.

Rámec umožňuje rôzne spôsoby konfigurácie: anotácie, XML alebo API.

Viac informácií o rámci sa nachádza v jeho dokumentácii.

Ak chcete zahrnúť JMapper do nášho projektu, musíme pridať jeho závislosť:

 com.googlecode.jmapper-framework jmapper-core 1.6.1.CR2 

3. TestovanieModel

Aby sme mohli mapovanie správne otestovať, musíme mať zdrojové a cieľové modely. Vytvorili sme dva testovacie modely.

Prvý z nich je iba jednoduché POJO s jedným String Toto nám umožnilo v jednoduchších prípadoch porovnávať rámce a skontrolovať, či sa niečo zmení, ak použijeme komplikovanejšie fazule.

Jednoduchý zdrojový model vyzerá takto:

verejná trieda SourceCode {reťazcový kód; // getter a setter}

A jeho cieľ je dosť podobný:

verejná trieda DestinationCode {reťazcový kód; // getter a setter}

Skutočný príklad zdroja fazule vyzerá takto:

verejná trieda SourceOrder {private String orderFinishDate; private PaymentType PaymentType; súkromná zľava na zľavu; súkromné ​​DeliveryData deliveryData; private User orderingUser; súkromný Zoznam objednaných produktov; súkromný obchod offerShop; private int orderId; súkromný stav OrderStatus; private LocalDate orderDate; // štandardné getre a setre}

A cieľová trieda vyzerá takto:

public class Order {private User orderingUser; súkromný Zoznam objednaných produktov; private OrderStatus orderStatus; private LocalDate orderDate; private LocalDate orderFinishDate; private PaymentType PaymentType; súkromná zľava Zľava; private int shopId; súkromné ​​DeliveryData deliveryData; súkromný obchod offerShop; // štandardné getre a setre}

Celú štruktúru modelu nájdete tu.

4. Prevodníky

Pre zjednodušenie návrhu testovacieho nastavenia sme vytvorili Prevádzač rozhranie:

prevodník verejného rozhrania {Prevod objednávky (SourceOrder sourceOrder); Konvertovať cieľový kód (SourceCode sourceCode); }

A toto rozhranie implementujú všetci naši vlastní mapovači.

4.1. OrikaConverter

Orika umožňuje úplnú implementáciu API, čo výrazne zjednodušuje tvorbu mapovača:

verejná trieda OrikaConverter implementuje Converter {private MapperFacade mapperFacade; public OrikaConverter () {MapperFactory mapperFactory = nový DefaultMapperFactory .Builder (). build (); mapperFactory.classMap (Order.class, SourceOrder.class) .field ("orderStatus", "status"). byDefault (). register (); mapperFacade = mapperFactory.getMapperFacade (); } @Override public Order convert (SourceOrder sourceOrder) {return mapperFacade.map (sourceOrder, Order.class); } @Override public DestinationCode convert (SourceCode sourceCode) {return mapperFacade.map (sourceCode, DestinationCode.class); }}

4.2. DozerConverter

Dozer vyžaduje mapovací súbor XML s nasledujúcimi časťami:

  com.baeldung.performancetests.model.source.SourceOrder com.baeldung.performancetests.model.destination.Order status stav objednávky    com.baeldung.performancetests.model.source.SourceCode com.baeldung.performancetests.model.destination.DestinationCode 

Po definovaní mapovania XML ho môžeme použiť z kódu:

verejná trieda DozerConverter implementuje Converter {private final Mapper mapper; public DozerConverter () {this.mapper = DozerBeanMapperBuilder.create () .withMappingFiles ("dozer-mapping.xml") .build (); } @Override public Order convert (SourceOrder sourceOrder) {return mapper.map (sourceOrder, Order.class); } @Override public DestinationCode convert (SourceCode sourceCode) {return mapper.map (sourceCode, DestinationCode.class); }}

4.3. MapStructConverter

Definícia MapStruct je dosť jednoduchá, pretože je úplne založená na generovaní kódu:

@Mapper verejné rozhranie MapStructConverter rozširuje Converter {MapStructConverter MAPPER = Mappers.getMapper (MapStructConverter.class); @Mapping (source = "status", target = "orderStatus") @Override Prevod objednávky (SourceOrder sourceOrder); @Override DestinationCode convert (SourceCode sourceCode); }

4.4. JMapperConverter

JMapperConverter vyžaduje viac práce. Po implementácii rozhrania:

verejná trieda JMapperConverter implementuje Converter {JMapper realLifeMapper; JMapper simpleMapper; public JMapperConverter () {JMapperAPI api = nový JMapperAPI () .add (JMapperAPI.mappedClass (Order.class)); realLifeMapper = nový JMapper (Order.class, SourceOrder.class, api); JMapperAPI simpleApi = nový JMapperAPI () .add (JMapperAPI.mappedClass (DestinationCode.class)); simpleMapper = nový JMapper (DestinationCode.class, SourceCode.class, simpleApi); } @Override public Order convert (SourceOrder sourceOrder) {return (Order) realLifeMapper.getDestination (sourceOrder); } @Override public DestinationCode convert (SourceCode sourceCode) {return (DestinationCode) simpleMapper.getDestination (sourceCode); }}

Musíme tiež pridať @JMap anotácie ku každému poľu cieľovej triedy. JMapper tiež nemôže sám prevádzať medzi typmi enum a vyžaduje od nás, aby sme vytvorili vlastné mapovacie funkcie:

@JMapConversion (from = "paymentType", to = "PaymentType") verejná konverzia PaymentType (typ com.baeldung.performancetests.model.source.PaymentType) {PaymentType paymentType = null; switch (type) {case CARD: PaymentType = PaymentType.CARD; prestávka; prípad CASH: PaymentType = PaymentType.CASH; prestávka; prípad TRANSFER: PaymentType = PaymentType.TRANSFER; prestávka; } vrátiť PaymentType; }

4.5. ModelMapperConverter

ModelMapperConverter vyžaduje, aby sme poskytovali iba triedy, ktoré chceme mapovať:

verejná trieda ModelMapperConverter implementuje Converter {private ModelMapper modelMapper; public ModelMapperConverter () {modelMapper = nový ModelMapper (); } @Override public Order convert (SourceOrder sourceOrder) {return modelMapper.map (sourceOrder, Order.class); } @Override public DestinationCode convert (SourceCode sourceCode) {return modelMapper.map (sourceCode, DestinationCode.class); }}

5. Jednoduché testovanie modelu

Na testovanie výkonu môžeme použiť Java Microbenchmark Harness, viac informácií o tom, ako ho používať, nájdete v tomto článku.

Pre každú z nich sme vytvorili samostatnú referenčnú hodnotu Prevádzač so špecifikáciou BenchmarkMode do Režim. Všetko.

5.1. Priemerný čas

Spoločnosť JMH vrátila nasledujúce výsledky pre priemerný čas chodu (čím menej, tým lepšie):

Názov rámcaPriemerná doba chodu (v ms na operáciu)
MapStruct10 -5
JMapper10 -5
Orika0.001
ModelMapper0.001
Buldozér0.002

Táto referenčná hodnota jasne ukazuje, že MapStruct aj JMapper majú najlepší priemerný pracovný čas.

5.2. Priepustnosť

V tomto režime porovnávacia hodnota vracia počet operácií za sekundu. Dostali sme nasledujúce výsledky (viac je lepšie) :

Názov rámcaPriepustnosť (v operáciách za ms)
MapStruct133719
JMapper106978
Orika1800
ModelMapper978
Buldozér471

V režime priepustnosti bol MapStruct najrýchlejší z testovaných rámcov, JMapper bol tesne za ním.

5.3. SingleShotTime

Tento režim umožňuje meranie času jednej operácie od jej začiatku do konca. Referenčná hodnota poskytla nasledujúci výsledok (menej je lepšie):

Názov rámcaČas jedného záberu (v ms na operáciu)
JMapper0.015
MapStruct0.450
Buldozér2.094
Orika2.898
ModelMapper4.837

Tu vidíme, že JMapper vráti lepší výsledok ako MapStruct.

5.4. Čas vzorkovania

Tento režim umožňuje vzorkovanie času každej operácie. Výsledky troch rôznych percentilov vyzerajú takto:

Ukážkový čas (v milisekundách na operáciu)
Názov rámca0,90 p0,999p1.0
JMapper10-40.0012.6
MapStruct10-40.0013
Orika0.0010.0104
ModelMapper0.0020.0153.2
Buldozér0.0030.02125

Všetky kritériá ukázali, že MapStruct a JMapper sú dobrou voľbou v závislosti od scenára.

6. Testovanie modelu v reálnom živote

Na testovanie výkonu môžeme použiť Java Microbenchmark Harness, viac informácií o tom, ako ho používať, nájdete v tomto článku.

Pre každú z nich sme vytvorili samostatnú referenčnú hodnotu Prevádzač so špecifikáciou BenchmarkMode do Režim. Všetko.

6.1. Priemerný čas

Spoločnosť JMH vrátila nasledujúce výsledky pre priemerný čas chodu (menej je lepšie):

Názov rámcaPriemerná doba chodu (v ms na operáciu)
MapStruct10 -4
JMapper10 -4
Orika0.004
ModelMapper0.059
Buldozér0.103

6.2. Priepustnosť

V tomto režime benchmark vráti počet operácií za sekundu. Pre každého z mapovačov sme dostali nasledujúce výsledky (viac je lepších):

Názov rámcaPriepustnosť (v operáciách za ms)
JMapper7691
MapStruct7120
Orika281
ModelMapper19
Buldozér10

6.3. SingleShotTime

Tento režim umožňuje meranie času jednej operácie od jej začiatku do konca. Referenčná hodnota priniesla nasledujúce výsledky (menej je lepších):

Názov rámcaČas jedného záberu (v ms na operáciu)
JMapper0.253
MapStruct0.532
Buldozér9.495
ModelMapper16.288
Orika18.081

6.4. Čas vzorkovania

Tento režim umožňuje vzorkovanie času každej operácie. Výsledky vzorkovania sú rozdelené na percentily. Uvádzame výsledky pre tri rôzne percentily p0,90, p0,999, a p1,00:

Ukážkový čas (v milisekundách na operáciu)
Názov rámca0,90 p0,999p1.0
JMapper10-30.00864
MapStruct10-30.01068
Orika0.0060.27832
ModelMapper0.0832.39897
Buldozér0.1464.526118

Presné výsledky jednoduchého príkladu a príkladu zo skutočného života boli síce zreteľne odlišné, sledujú však viac-menej rovnaký trend. V obidvoch príkladoch sme videli tesnú súťaž medzi JMapper a MapStruct o najvyššie miesto.

6.5. Záver

Na základe testovania reálneho modelu, ktoré sme vykonali v tejto časti, vidíme, že najlepší výkon jednoznačne patrí JMapperu, hoci MapStruct je tesne za ním. V rovnakých testoch vidíme, že Dozer je až na koniec našej tabuľky výsledkov neustále na konci SingleShotTime.

7. Zhrnutie

V tomto článku sme vykonali testy výkonu piatich populárnych rámcov mapovania fazule Java: ModelMapper, MapStruct, Orika, Dozer a JMapper.

Ako vždy, vzorky kódu nájdete na GitHub.


$config[zx-auto] not found$config[zx-overlay] not found