Több modulból álló Maven projektek
Korábbi bejegyzéseinkben megismerkedhettél a legfontosabb Maven komponensekkel, s most szeretném bemutatni, hogy hogyan lehet több modulból álló Maven projektet (multi-module project) létrehozni, melynek segítségével többrétegű alkalmazások készíthetők.
De miért is jó, ha több modulba szervezzük projektjeinket? Alapvetően a Java projektek osztályait package-ekbe szokás szervezni, ezzel könnyebben átláthatóvá téve a projektet. Ám egy-egy nagyobb projekt több ezer osztályt, s több száz package-et is tartalmazhat, s ez indokolttá teheti egy újabb absztrakció bevezetését a projekt szerkezetébe. Egy projekten belül lehetőségünk van rá, hogy az alkalmazás fő funkcionalitásai mentén modulokba szervezzük a package-eket és az osztályokat. Tipikusan a többrétegű alkalmazások fejlesztése során használható ilyen projektstruktúra. Például az adatbázisműveletek, a háttérfolyamatok és a kezelőfelület forrásállományai is külön modulokba célszerű helyezni. A többrétegű, vagy MVC (Model-View-Controller) architektúrájú alkalmazásokról a tizennégyhetes online alaptréningen (amire itt tudsz jelentkezni) olvashatsz bővebben. A Maven segítségével szerencsére pofonegyszerűen készíthetünk multi-modul projekteket.
Egy multi-module projekt felépítése
Egy MVC architektúrájú, multi-modulos projekt esetén az alábbi módon nézhet ki a projekt könyvtárszerkezete:
Amint láthatod, a projekt pom fájlon kívül, minden modul rendelkezik egy pom fájllal. A modulok felépítése alapvetően ugyanolyan, mint a korábban megismert modul nélküli projekteké. Tehát kvázi, mintha több kicsi helloworld-öt kapcsolnánk logikailag össze. Minden modulban található egy-egy src könyvtár, mely tartalmaz egy main (forrásállományok) és egy test (tesztek) mappát.
A projekt pom fájlban definiált dependenciák, property-k, pluginek, stb. minden modulban érvényesek lesznek. Továbbá itt kell megadni, hogy projektünk milyen modulokat tartalmaz (<modules> tag-ek közt). Ezt, a fenti ábrán bemutatott projekt esetében az alábbi kód segítségével tehetjük meg:
<modules>
<module>model</module>
<module>controller</module>
<module>view</module>
</modules>
Továbbá a projekt packaging módját pom-ra kell állítani:
<packaging>pom</packaging>
Minden modul pomjában meg kell adni az őt tartalmazó projekt adatait, a tag-ek közt:
<parent>
<artifactId>demo</artifactId>
<groupId>hu.zerotohero</groupId>
<version>${project.version}</version>
</parent>
Amennyiben egy modulban szeretnénk használni egy másik modul osztályait, akkor azt dependenciaként kell sorolni az adott modulban. Például ha a controller modulban akarjuk használni a model modul tartalmát akkor az alábbi dependenciát kell megadni a controller pomjában:
<dependency>
<groupId>hu.zerotohero</groupId>
<artifactId>model</artifactId>
<version>${project.version}</version>
</dependency>
Öröklődés
Ahogy azt már korábban említettem az egyes modulok pom-jai öröklik a szülőik pomjainak tartalmát. Vagyis a korábbi példa esetében, a model, a view és a controller pomjai is örökölték a projekt pom-jának tartalmát. Ezen felül maga a projekt pom is örökölt az úgynevezett Super Pom-tól, mely a Maven default pom-ja. A Super Pom-ot minden pom fájl megörökli implicit, vagy explicit módon (jelen esetben a projekt pom-on keresztül öröklik meg a modulok pom-jai). A Maven több szintű öröklődést is tud kezelni, vagyis, ha a modulokon belül lennének még modulok, akkor azok pom-jai nem csak a szülő pom tartalmát, de a projekt pom-ot és a Super Pom-ot is örökölnék. Emiatt, hogy több szintről tudunk örököltetni benne dolgokat, okozhatunk magunknak néhány kellemetlen órát, ha ugyanabból a dependenciából két különböző verziót használunk, ugyanis valamelyik library problémázni fog, és ilyenkor általában elhangzik a következő mondat a fejlesztő szájából : ” hát ez hülye, itt van bíííp, pont itt van behúzva te bíííp”… :) tehát nem árt átgondolni, a struktúrát a dependenciákat illetően.
A Super Pom mellett az előző bejegyzésben bemutatott settings.xml tartalmát is örökli a projekt minden pom fájlja.
Az öröklődéssel összerakott leíróhalmazt nevezzük effective POM-nak. Az effective POM tartalmaz minden leírót, amit az adott POM használatakor a maven fel fog oldani az öröklődésben.
Hogyan nézzük meg az effective pom-ot?
- Console:
mvn help:effective-pom
- Eclipse:
A pom fájlt megnyitod, és lesz egy olyan “füled”, hogy Effective Pom.
- Idea:
A pom fájlon jobb klikk -> Maven -> “Show Effective POM”
Problémás eset
Mit kell tennünk, ha egy dependencia hoz magával egy másik dependenciát (tranzitív dependencia), de arra a „másikra” nincs szükségünk a projektünkben?
Előfordult a következő: vaadin-os compile widgetset elhasal, és mi csak annyit látunk a git historyban, hogy bekerült pár újabb dependencia, config nem változott, és értetlenül nézünk az eset elé. No de nem túl sokáig, hiszen van a mavennek egy -X kapcsolója, valamint lelkesen elkezdünk kutatni, hogy „mi a bíííp lehet ezzel a bííííppel?!”
Majd 1-2 óra elteltével megvan a ludas, jött egy jasperreports-os dependency, aminek van egy jdtcore „hozománya”, és ez cseszi szét a compile-t. Mi legyen a megoldás? A jasperre szükségünk van, okkal használjuk ennél a projektnél, ki mégsem dobhatjuk…
Exclusion a megoldás:
<dependency>
<groupId>net.sf.jasperreports</groupId>
<artifactId>jasperreports</artifactId>
<version>${jasperReports.version}</version>
<exclusions>
<exclusion>
<artifactId>jdtcore</artifactId>
<groupId>eclipse</groupId>
</exclusion>
</exclusions>
</dependency>