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) |
---|---|
MapStruct | 10 -5 |
JMapper | 10 -5 |
Orika | 0.001 |
ModelMapper | 0.001 |
Dózer | 0.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) |
---|---|
MapStruct | 133719 |
JMapper | 106978 |
Orika | 1800 |
ModelMapper | 978 |
Dózer | 471 |
Á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 neve | Single Shot Time (ms / művelet) |
---|---|
JMapper | 0.015 |
MapStruct | 0.450 |
Dózer | 2.094 |
Orika | 2.898 |
ModelMapper | 4.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 neve | p0.90 | p.999 | p1.0 |
JMapper | 10-4 | 0.001 | 2.6 |
MapStruct | 10-4 | 0.001 | 3 |
Orika | 0.001 | 0.010 | 4 |
ModelMapper | 0.002 | 0.015 | 3.2 |
Dózer | 0.003 | 0.021 | 25 |
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) |
---|---|
MapStruct | 10 -4 |
JMapper | 10 -4 |
Orika | 0.004 |
ModelMapper | 0.059 |
Dózer | 0.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) |
---|---|
JMapper | 7691 |
MapStruct | 7120 |
Orika | 281 |
ModelMapper | 19 |
Dózer | 10 |
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 neve | Single Shot Time (ms / művelet) |
---|---|
JMapper | 0.253 |
MapStruct | 0.532 |
Dózer | 9.495 |
ModelMapper | 16.288 |
Orika | 18.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 neve | p0.90 | p.999 | p1.0 |
JMapper | 10-3 | 0.008 | 64 |
MapStruct | 10-3 | 0.010 | 68 |
Orika | 0.006 | 0.278 | 32 |
ModelMapper | 0.083 | 2.398 | 97 |
Dózer | 0.146 | 4.526 | 118 |
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.