Java Mapping Frameworks teljesítménye

1. Bevezetés

Több rétegből álló nagy Java-alkalmazások létrehozásához több modell, például perzisztencia-modell, tartomány-modell vagy úgynevezett DTO-k használata szükséges. Több modell használata különböző alkalmazási rétegekhez megköveteli, hogy biztosítsunk egy módszert a babok közötti feltérképezésre.

Ha ezt manuálisan végzi, gyorsan létrehozhat sok kazánlap kódot, és sok időt vesz igénybe. Szerencsénkre több objektum-leképezési keretrendszer létezik a Java számára.

Ebben az oktatóanyagban összehasonlítani fogjuk a legnépszerűbb Java leképezési keretrendszerek teljesítményét.

2. Keretek feltérképezése

2.1. Dózer

A dózer olyan leképezési keretrendszer, amely rekurzióval másolja az adatokat egyik objektumból a másikba. A keretrendszer nemcsak a tulajdonságok másolására képes a bab között, hanem automatikusan átalakíthat a különböző típusok között is.

A Dozer keretrendszer használatához hozzá kell adnunk egy ilyen függőséget a projektünkhöz:

 com.github.dozermapper dózermagos 6.5.0 

További információ a Dozer keretrendszer használatáról ebben a cikkben található.

A keretrendszer dokumentációja itt található.

2.2. Orika

Az Orika egy bab-bab leképezési keretrendszer, amely rekurzív módon másolja az adatokat egyik objektumból a másikba.

Az Orika általános elve hasonló a Dozerhez. A fő különbség a kettő között az a tény, hogy Orika bytecode generációt használ. Ez lehetővé teszi gyorsabb térképezők létrehozását, minimális rezsivel.

Használatáhozhozzá kell adnunk egy ilyen függőséget a projektünkhöz:

 ma.glasnost.orika orika-core 1.5.4 

Az Orika használatáról részletesebb információk találhatók ebben a cikkben.

A keretrendszer tényleges dokumentációja itt található.

2.3. MapStruct

A MapStruct az egy kódgenerátor, amely automatikusan generálja a bean mapper osztályokat.

A MapStruct képes átalakítani a különböző adattípusokat is. További információ a használatáról ebben a cikkben található.

A MapStruct hozzáadásaprojektünkhöz a következő függőséget kell tartalmaznunk:

 org.mapstruct mapstruct 1.3.1.Végső 

A keretrendszer dokumentációja itt található.

2.4. ModelMapper

A ModelMapper egy olyan keretrendszer, amelynek célja az objektum-hozzárendelés egyszerűsítése, azáltal, hogy meghatározza, hogy az objektumok hogyan viszonyulnak egymáshoz konvenciók alapján. Típusbiztonságos és visszafogásbiztos API-t biztosít.

További információ a keretrendszerről a dokumentációban található.

A ModelMapper projektbe történő felvételéhez hozzá kell adnunk a következő függőséget:

 org.modelmapper modelmapper 2.3.8 

2.5. JMapper

A JMapper egy olyan leképezési keretrendszer, amelynek célja egy könnyen használható, nagy teljesítményű leképezés biztosítása a Java Beans között.

A keretrendszer célja a DRY elv alkalmazása Annotációk és relációs leképezés segítségével.

A keretrendszer különböző konfigurációs módokat tesz lehetővé: annotáció alapú, XML vagy API alapú.

További információ a keretrendszerről annak dokumentációjában található.

A JMapper bevonásához a projektünkbe hozzá kell adnunk a függőségét:

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

3. TesztelésModell

A térképezés megfelelő teszteléséhez forrás- és célmodellekkel kell rendelkeznünk. Két tesztmodellt hoztunk létre.

Az első csak egy egyszerű POJO Húr Ez lehetővé tette számunkra, hogy egyszerűbb esetekben összehasonlítsuk a keretrendszereket, és ellenőrizzük, hogy változik-e valami, ha bonyolultabb babot használunk.

Az egyszerű forrásmodell az alábbiak szerint néz ki:

public class SourceCode {Karaktersorozat; // getter és setter}

Célja pedig meglehetősen hasonló:

public class DestinationCode {String kód; // getter és setter}

A forrásbab valós példája így néz ki:

public class SourceOrder {private String orderFinishDate; privát PaymentType paymentType; privát Kedvezmény kedvezmény; privát DeliveryData deliveryData; privát Felhasználó orderingUser; privát Lista megrendeltTermékek; privát üzlet kínálBolt; private int orderId; privát OrderStatus állapot; privát LocalDate orderDate; // szabványos mérőeszközök és beállítók}

És a célosztály az alábbiak szerint néz ki:

public class Rendelés {private User orderingUser; privát Lista megrendeltTermékek; privát OrderStatus orderStatus; privát LocalDate orderDate; privát LocalDate orderFinishDate; privát PaymentType paymentType; privát Kedvezmény kedvezmény; private int shopId; privát DeliveryData deliveryData; privát üzlet kínálBolt; // szabványos mérőeszközök és beállítók}

A teljes modellszerkezet itt található.

4. Átalakítók

A tesztelési beállítások egyszerűsítése érdekében létrehoztuk a Átalakító felület:

nyilvános felület Converter {Order convert (SourceOrder sourceOrder); DestinationCode convert (SourceCode sourceCode); }

És minden egyedi hozzárendelőnk megvalósítja ezt a felületet.

4.1. OrikaConverter

Az Orika lehetővé teszi az API teljes megvalósítását, ez jelentősen leegyszerűsíti a térképkészítő létrehozását:

public class OrikaConverter implementálja a Converter {private MapperFacade mapperFacade; public OrikaConverter () {MapperFactory mapperFactory = new DefaultMapperFactory .Builder (). build (); mapperFactory.classMap (Order.class, SourceOrder.class) .field ("orderStatus", "status"). byDefault (). register (); mapperFacade = mapperFactory.getMapperFacade (); } @Orride 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

A dózerhez XML-leképezési fájl szükséges, a következő szakaszokkal:

  com.baeldung.performancetests.model.source.SourceOrder com.baeldung.performancetests.model.destination.Order status rendelés állapota    com.baeldung.performancetests.model.source.SourceCode com.baeldung.performancetests.model.destination.DestinationCode 

Az XML leképezés meghatározása után kódból használhatjuk:

public class DozerConverter implementálja a Converter {privát végleges Mapper mappert; public DozerConverter () {this.mapper = DozerBeanMapperBuilder.create () .withMappingFiles ("dozer-mapping.xml") .build (); } @Orride 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

A MapStruct meghatározása meglehetősen egyszerű, mivel teljes egészében a kódgeneráláson alapul:

@Mapper nyilvános felület A MapStructConverter kiterjeszti az átalakítót {MapStructConverter MAPPER = Mappers.getMapper (MapStructConverter.class); @Mapping (source = "status", target = "orderStatus") @Orride Order convert (SourceOrder sourceOrder); @Orride DestinationCode convert (SourceCode sourceCode); }

4.4. JMapperConverter

JMapperConverter több munkát igényel. Az interfész megvalósítása után:

nyilvános osztályú JMapperConverter megvalósítja a Converter {JMapper realLifeMapper; JMapper simpleMapper; public JMapperConverter () {JMapperAPI api = new JMapperAPI () .add (JMapperAPI.mappedClass (Order.class)); realLifeMapper = új JMapper (Order.class, SourceOrder.class, api); JMapperAPI simpleApi = új JMapperAPI () .add (JMapperAPI.mappedClass (DestinationCode.class)); simpleMapper = new JMapper (DestinationCode.class, SourceCode.class, simpleApi); } @Orride public order convert (SourceOrder sourceOrder) {return (Order) realLifeMapper.getDestination (sourceOrder); } @Override public DestinationCode convert (SourceCode sourceCode) {return (DestinationCode) simpleMapper.getDestination (sourceCode); }}

Azt is hozzá kell tennünk @JMap annotációk a célosztály minden mezőjéhez. Ezenkívül a JMapper nem képes önállóan konvertálni az enum típusok között, és egyedi hozzárendelési függvényeket kell létrehoznunk:

@JMapConversion (from = "paymentType", to = "paymentType") nyilvános PaymentType konverzió (com.baeldung.performancetests.model.source.PaymentType típus) {PaymentType paymentType = null; kapcsoló (típus) {case CARD: paymentType = PaymentType.CARD; szünet; ügy CASH: paymentType = PaymentType.CASH; szünet; eset TRANSFER: paymentType = PaymentType.TRANSFER; szünet; } return paymentType; }

4.5. ModelMapperConverter

ModelMapperConverter megköveteli tőlünk, hogy csak azokat az osztályokat biztosítsuk, amelyeket fel akarunk térképezni:

public class ModelMapperConverter megvalósítja a Converter {private ModelMapper modelMapper; public ModelMapperConverter () {modelMapper = new ModelMapper (); } @Orride public order convert (SourceOrder sourceOrder) {return modelMapper.map (sourceOrder, Order.class); } @Override public DestinationCode convert (SourceCode sourceCode) {return modelMapper.map (sourceCode, DestinationCode.class); }}

5. Egyszerű modelltesztelés

A teljesítmény teszteléséhez használhatjuk a Java Microbenchmark Harness programot, további információk a használatáról ebben a cikkben találhatók.

Mindegyikhez külön referenciaértéket hoztunk létre Átalakító megadásával BenchmarkMode nak nek Mód. Mind.

5.1. Átlagos idő

A JMH a következő eredményeket adta az átlagos futási időre (minél kisebb, annál jobb):

Keret neveÁtlagos futási idő (ms / művelet)
MapStruct10 -5
JMapper10 -5
Orika0.001
ModelMapper0.001
Dózer0.002

Ez a referenciaérték világosan mutatja, hogy a MapStruct és a JMapper is a legjobb átlagos munkaidővel rendelkezik.

5.2. Átbocsátás

Ebben a módban a referenciaérték másodpercenként adja vissza a műveletek számát. A következő eredményeket kaptuk (több a jobb) :

Keret neveÁtbocsátás (műveletek / ms)
MapStruct133719
JMapper106978
Orika1800
ModelMapper978
Dózer471

Átviteli módban a MapStruct volt a leggyorsabb a tesztelt keretek között, a JMapper pedig szoros másodperccel.

5.3. SingleShotTime

Ez az üzemmód lehetővé teszi az egyes műveletek idejének mérését az elejétől a végéig. A referenciaérték a következő eredményt adta (kevesebb a jobb):

Keret neveSingle Shot Time (ms / művelet)
JMapper0.015
MapStruct0.450
Dózer2.094
Orika2.898
ModelMapper4.837

Itt azt látjuk, hogy a JMapper jobb eredményt ad, mint a MapStruct.

5.4. SampleTime

Ez az üzemmód lehetővé teszi az egyes műveletek idejének mintavételét. Három különböző percentilis eredményei az alábbiak szerint néznek ki:

Mintaidő (műveletenként milliszekundumban)
Keret nevep0.90p.999p1.0
JMapper10-40.0012.6
MapStruct10-40.0013
Orika0.0010.0104
ModelMapper0.0020.0153.2
Dózer0.0030.02125

Valamennyi benchmark megmutatta, hogy a MapStruct és a JMapper egyaránt jó választás a forgatókönyvtől függően.

6. Valós életű modell tesztelése

A teljesítmény teszteléséhez használhatjuk a Java Microbenchmark Harness alkalmazást, további információk a használatáról ebben a cikkben találhatók.

Mindegyikhez külön referenciaértéket hoztunk létre Átalakító megadásával BenchmarkMode nak nek Mód. Mind.

6.1. Átlagos idő

A JMH a következő eredményeket adta az átlagos futási időre (a kevesebb jobb):

Keret neveÁtlagos futási idő (ms / művelet)
MapStruct10 -4
JMapper10 -4
Orika0.004
ModelMapper0.059
Dózer0.103

6.2. Átbocsátás

Ebben a módban a referenciaérték másodpercenként adja vissza a műveletek számát. Az egyes leképezőkről a következő eredményeket kaptuk (a több jobb):

Keret neveÁtbocsátás (műveletek / ms)
JMapper7691
MapStruct7120
Orika281
ModelMapper19
Dózer10

6.3. SingleShotTime

Ez az üzemmód lehetővé teszi az egyes műveletek idejének mérését az elejétől a végéig. A benchmark a következő eredményeket adta (kevesebb a jobb):

Keret neveSingle Shot Time (ms / művelet)
JMapper0.253
MapStruct0.532
Dózer9.495
ModelMapper16.288
Orika18.081

6.4. SampleTime

Ez az üzemmód lehetővé teszi az egyes műveletek idejének mintavételét. A mintavételi eredményeket százalékokra osztjuk, három különböző százalékra mutatjuk be az eredményeket: p0.90, p0.999, és p1.00:

Mintaidő (műveletenként milliszekundumban)
Keret nevep0.90p.999p1.0
JMapper10-30.00864
MapStruct10-30.01068
Orika0.0060.27832
ModelMapper0.0832.39897
Dózer0.1464.526118

Míg az egyszerű és a valós példa pontos eredményei egyértelműen különböztek, de nagyjából ugyanazt a tendenciát követik. Mindkét példában szoros versenyt láttunk a JMapper és a MapStruct között az első helyért.

6.5. Következtetés

Az ebben a szakaszban elvégzett valós modelltesztek alapján láthatjuk, hogy a legjobb teljesítmény egyértelműen a JMapperé, bár a MapStruct szoros második. Ugyanezekben a tesztekben azt látjuk, hogy a Dozer következetesen az eredménytáblázatunk végén van, kivéve SingleShotTime.

7. Összegzés

Ebben a cikkben öt népszerű Java-bab-leképezési keret teljesítménytesztjét hajtottuk végre: a ModelMapper-et, MapStruct, Orika, Dózer és JMapper.

Mint mindig, a kódminták megtalálhatók a GitHubon.