Teil 2

Buildsysteme im Vergleich: Maven

Mit Apache Ant konnten alle gestellten Anforderungen erfüllt werden. Wie zu erkennen, ist schon bei diesem kleinen Projekt einiges an Tipparbeit notwendig. Die Tatsache, dass es zig Wege zur Realisierung der gesetzten Anforderungen gibt, kann in einem wachsendem Projekt doch schnell zur Unübersichtlichkeit führen.

Apache Maven geht hier einen anderen Weg. Als Basiskonzept gilt: „Convention over Configuration“. Vieles wird über Vorgaben (Conventions) geregelt und somit muss der Entwickler nur noch wenige Anpassungen (Configuration) vornehmen. Der scheinbare Nachteil ist, dass sich das Projekt an die Struktur eines Maven-Projekts anpassen muss. Um auch längere Projektlaufzeiten zu gewährleisten und Fluktuationen im Projektteam auszugleichen, sollten Projekte einen gewissen Standard befolgen, damit der Build von allen Teammitgliedern gewartet werden kann. Somit kann man sich an den Standard von Maven halten, er wird inzwischen auch in vielen Java-Projekten angewendet. Das Prinzip von Maven fußt auf der Annahme, die auch für viele Projekte zutrifft, dass das Erzeugen von Softwareprojekten meist in gleichen Schritten erfolgt. Diese Schritte hat Maven in einem Lebenszyklus (build life cycle) zusammengefasst, der aus mehreren Phasen (z. B.compile) besteht. Die kleinste Ausführungseinheit bei Maven ist das Goal. Mehrere Goals sind zu einer Phase zusammengefasst.

Die aktuelle Version 2.2.1 von Maven kann über die Downloadseite des Projekts direkt als Archiv heruntergeladen werden. Nach dem Entpacken (entpackte Distribution siehe Abb. 4) kann Maven über das Kommandozeilenskript mvn (Verzeichnis bin in der Distribution) ausgeführt werden. Für den ersten Test der Installation kann über den Befehl mvn -version die Version des eingesetzten Maven ausgegeben werden.

Abb. 4: Entpackte Distribution von Apache Maven 2.2.1

Bei Ant wird von einem Build-Skript gesprochen, bei Maven handelt es sich eher um eine Build-Konfiguration. Der Name dieser Datei lautet pom.xml. POM steht in diesem Zusammenhang für Project Object Model. Beim Neustart mit einem Projekt bietet Maven einen Templatemechanismus an, um solch eine POM und die zugehörige Verzeichnisstruktur zu erzeugen. Über den Aufruf mvn archetype:create -DgroupId=de.javamagazin.buildsysteme -DartifactId=testprojekt wird der mitgelieferte Archetype verwendet und ein Projekt nach dieser Vorlage erzeugt. Sollte es vorkommen, dass häufig neue Projekte angelegt werden, bietet es sich an, einen eigenen Archetype zu definieren. Dies ist sehr gut in dem freien E-Book „Better Builds with Maven“ beschrieben.

In unserem Beispielprojekt existiert die Struktur schon, und somit wird die POM von Hand erstellt. Als Ausgangsbasis kann die abgebildete POM der kurzen Onlinedokumentation entnommen werden. Im Gegensatz zu Ant kommt Maven bereits standardmäßig mit Dependency Management. Für die Erstellung der POM werden nun die notwendigen Angaben zu den verwendeten Bibliotheken benötigt, um sie innerhalb des Blocks dependencies zu pflegen. Für das Projekt core wird Commons Lang in der Version 2.4 benötigt. Um die Angaben für die Pflege der Abhängigkeiten nicht auswendig zu lernen, können diese z. B. über das kostenlose Onlineverzeichnis MVNRepository ermittelt werden. Neben Metadaten wie Versionsnummer ist für das Projekt core noch dascompile-Plug-in anzupassen. Listing 3 enthält die pom.xml, um das Projekt core zu erzeugen. Über mvn compile wird die Phase compile ausgeführt und das Projekt übersetzt. Bei der Ausführung dieses Kommandos werden zunächst die Abhängigkeiten aus einem Maven Repository geladen. Im Fall der Standardkonfiguration ist dieses Repository das Maven Central Repository.

[ header = Seite 2: Maven – Wohin mit privaten Bibliotheken? ]

"><project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>buildsysteme</groupId>
<artifactId>core</artifactId>
<packaging>jar</packaging>
<version>1.0.0</version>
<name>The core module</name>

<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>2.0.2</version>
<configuration>
<source>1.5</source>
<target>1.5</target>
</configuration>
</plugin>
</plugins>
</build>


<dependencies>
<dependency>
<groupId>commons-lang</groupId>
<artifactId>commons-lang</artifactId>
<version>2.4</version>
</dependency>
</dependencies>

</project>
Maven – Wohin mit privaten Bibliotheken?
Beim Einstieg mit Maven und dessen Dependency Management wird man zunächst dasMaven Central Repository als Quelle für die Abhängigkeiten wählen. Mit zunehmender Projektlaufzeit wird der Moment kommen, an dem selbsterzeugte Artefakte wiederverwendet werden sollen. Diese Wiederverwendung sollte auch über den Mechanismus von Maven erfolgen. Um ein selbsterzeugtes Artefakt als Abhängigkeit einzutragen, muss es in einem Repository zur Verfügung stehen. Für den lokalen Entwicklungsrechner kann über mvn install das Artefakt in das lokale Repository installiert werden. Für die Verwendung über den lokalen Entwicklungsrechner hinaus reicht diese Variante aber nicht aus. Hier hilft mvn deploy weiter. Damit wird das Artefakt in das remote-Repository installiert. Da in das Maven Central Repository nicht einfach ein Artefakt installiert werden kann und die meisten Projekte die Artefakte nur intern verwenden können und wollen, dient als Alternative ein interner Repository Manager. Drei kostenlose Vertreter dieser Art sindArchiva, Artifactory und Nexus. Neben der Funktion des internen Repositories können sie auch eine Proxy-Funktion übernehmen. Damit wird vermieden, dass von jedem Rechner ein Zugriff auf das öffentliche Repository im Internet vorgenommen wird.
Die Konfiguration wird in der settings.xml von Maven vorgenommen. Genaue Informationen dazu können der Dokumentation ( hier, hier und hier) des jeweiligen Repository Managers entnommen werden.

Über die Phase test werden alle Testklassen innerhalb von src/test/java ausgeführt. Für die Ausführung wird als zusätzliche Abhängigkeit JUnit (siehe nachfolgender Code) benötigt. Bei der Definition einer Abhängigkeit kann gesteuert werden, für welche Phase (Element scope) eine Bibliothek benötigt wird. In diesem Fall wird JUnit nur für test benötigt. Mit der Ausführung von mvn test werden die Quellen übersetzt und die Tests ausgeführt:

<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.7</version>
<scope>test</scope>
</dependency>

In den Metadaten der POM wird gesteuert, welche Art (Element packaging) von Zielartefakt erzeugt werden soll. Im Fall von core und richclient steht dieses Element auf dem Wert jar. Beim Projektwebclient ist war die richtige Konfigurationseinstellung. Über den Aufruf von mvn package wird das Zielartefakt im Verzeichnis target erzeugt, wodurch automatisch die Tests ausgeführt werden. Wenn sie fehlschlagen, wird das Artefakt nicht erzeugt. Über eine Umgebungsvariable ist es möglich, die Ausführung der Tests zu unterbinden. Folgender Aufruf erzeugt das Zielartefakt ohne Ausführung von Tests: mvn package -Dmaven.test.skip=true. Nach der Ausführung liegt das jar-Archiv im Verzeichnis target.

Das Archiv enthält ein Standard-Manifest. Um Attribute hinzuzufügen, muss das jar-Plug-in konfiguriert werden, und zwar innerhalb des Blocks build. Folgendes Listing zeigt die Konfiguration für das Projekt core:

<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<version>2.2</version>
<configuration>
<archive>
<manifestEntries>
<Implementation-Version>${project.version}</Implementation-Version>
</manifestEntries>
</archive>
</configuration>
</plugin>

[ header = Seite 3: Listing 4 & Listing 5 ]

Nach dem Erzeugen der Bibliothek core muss sie zur Verwendung in den anderen Projekten im lokalen Repository installiert werden. Dies erfolgt über den Aufruf mvn install. Nun kann die Bibliothek core gemäß den angegebenen Metadaten in deren POM in anderen Projekten eingebunden werden:

<dependency>
<groupId>buildsysteme</groupId>
<artifactId>core</artifactId>
<version>1.0.0</version>
</dependency>

Für die Erzeugung des Projekts webclient werden zusätzliche Bibliotheken benötigt, die aber nicht im war-Archiv landen dürfen. Hierfür wird bei den Abhängigkeiten das Element scope gesetzt. Für die Übersetzung wird u. a. das Serlvet-API benötigt. Gemäß JEE-Spezifikation darf dies aber nicht im WEB-INF/lib enthalten sein. Deshalb wird hier das Element scope auf compile gesetzt. Die zusätzlichen Abhängigkeiten sind in Listing 4 abgebildet:

<dependency>?>
<groupId>javax.servlet</groupId>
<artifactId>servlet-api</artifactId>?>
<version>2.5</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>3.0.0.RELEASE</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>3.0.0.RELEASE</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>3.0.0.RELEASE</version>
<scope>test</scope>
</dependency>

Um Checkstyle auszuführen (Anforderung 6), ist lediglich der Aufruf checkstyle:checkstyle notwendig. Für eine Automatisierung muss Checkstyle an eine Lebensphase geknüpft werden. Über den Aufruf mvn site wird die bekannte Projektseite erzeugt. Im Bereich reporting der POM kann angegeben werden, welche Plug-ins ausgeführt werden. Für dieses Beispiel bietet sich Surefire zur Erzeugung der JUnit-Reports und Checkstyle zur Erzeugung des Checkstyle-Berichts ( Abb. 5) an. Listing 5 zeigt die Konfiguration der beiden genannten Plug-ins im Bereich reporting.

<reporting>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-checkstyle-plugin</artifactId>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-report-plugin</artifactId>
</plugin>
</plugins>
</reporting>

Abb. 5: Checkstyle in der von Maven generierten Projektseite

[ header = Seite 4: Maven 3 – Was bringt die neue Version? ]

Mit der bisherigen Umsetzung können lediglich die Einzelprojekte erzeugt werden. Um mit einem Aufruf alle drei Projekte zu erzeugen, wird eine POM im Oberverzeichnis benötigt. Das Besondere daran ist, dass hier als packaging der Wert pom anzugeben ist. Im Bereich modules sind die Subprojekte definiert. Listing 6 zeigt die Umsetzung.

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>buildsysteme</groupId>
<artifactId>buildsysteme</artifactId>
<packaging>pom</packaging>

<version>1.0.0</version>
<name>parent project</name>

<modules>
<module>core</module>
<module>richclient</module>
<module>webclient</module>
</modules>
</project>
Maven 3 – Was bringt die neue Version?
Die Änderungen am aktuellen Release von Maven haben sich in letzter Zeit in Grenzen gehalten. Dies liegt wohl auch daran, dass derzeit am dritten Major-Release gearbeitet wird. Die erste Frage, die sich bei solch einem Versionssprung stellt, sind die Altprojekte. Besonders im Hinblick darauf, dass der Wechsel von Version 1 auf 2 nicht ohne erheblichen Aufwand machbar war. Dies haben sich die Entwickler, an vorderster Front Jason van Zyl, zu Herzen genommen und sich eine 100 %ige Kompatibilität zu Maven 2 auf die Fahnen geschrieben. Bis zu Maven 3.0 GA (aktuelle Version: 3.0-alpha-6) sollen 600 Integrationstests die Rückwärtskompatibilität absichern. Mit dem Sprung zu Version 3 soll das Ziel erreicht werden, ein einfacheres Maven zu bekommen, um noch mehr Entwickler von Maven zu überzeugen. Dies soll durch weniger Module und ein einfacheres und erweitertes Abhängigkeitssystem realisiert werden.
Bisher wird die Build-Konfiguration von Maven mittels XML vorgenommen. Dies wird in Maven 3 weiterhin möglich sein, daneben kommt aber durch Polyglot Maven die Möglichkeit hinzu, andere Sprachen wie Groovy, Scala, Clojure oder auch Ruby zu verwenden. Intern wird Maven nicht mehr Plexus, sondern Guice verwenden. EineBegründung ist auf dem Blog von Sonatype zu finden. Weitere Details zu Maven 3 können der Präsentation von Jason van Zyl entnommen werden. Ein genaues Erscheinungsdatum von Maven 3 ist bisher noch nicht bekannt. Die aktuelle Alphaversion kann von der Downloadseite von Maven heruntergeladen werden.

Im nächsten und letzten Teil dieser Serie widmen wir uns Gradle, dem noch recht jungen Groovy-Build-Tool. Außerdem folgt dann auch ein Fazit zum Vergleich der drei Kandidaten.

Markus Stäuble ist Senior IT-Consultant bei der MRM Worldwide GmbH. Er schreibt regelmäßig Artikel für diverse Fachzeitschriften und gibt sein Wissen gerne in Vorträgen wieder.
Geschrieben von
Kommentare

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht.