Skip to content

Introduktion till Maven

chilmers edited this page Jun 10, 2012 · 3 revisions

Detta är en kort introduktion för att snabbt få en överblick av byggsystemet Maven. Maven används för att kompilera och bygga ihop system-artefakter (till exempel .jar-, .war- och .ear-filer)

Deklarativt byggsystem

Maven skiljer sig från till exempel ANT i det att Maven har ett deklarativt sätt att beskriva ett bygge. Det betyder att man beskriver vad man behöver istället för hur det skall uppnås. Till exempel så säger man i Mavens byggfil att "Det här bygget skall generera en jar-fil" istället för att skriva proceduren som bygger ihop en jar-fil.

Konvention över konfiguration

Maven använder sig av "konvention över konfiguration" som innebär att om man inte konfigurerar en viss aspekt av bygget så får man i de allra flesta fall ett rimligt standardvärde på den parametern enligt konvention. I många fall behöver man inte lägga till mer än den allra nödvändigaste konfigurationen. Ett exempel kan vara att om jag inte beskriver exakt vilka filer som skall byggas in i en jar-fil så tar den den Java-källkod som finns. Jämför med till exempel Ant där allt måste beskrivas till punkt och pricka.

Beroendenhantering (dependency management)

En otroligt bra funktion i Maven är att man inte behöver kopiera och hålla ordning på jar-filer till de projekt man är beroende av. Dessa beroenden deklareras istället i Mavens byggfil (pom.xml) och pekas ut i ett Maven-repository (förråd av fördigbyggda jar-filer).

Maven-repository

När man installerar Maven så skapar den också ett lokalt repository (~/.m2/repository) för att förvara dina egna byggen i men också för att hålla en cache av andra beroenden. Av konvention så letar Maven efter beroenden först i ditt lokala repository och sedan i det centrala Maven-repositoryt (http://repo1.maven.org/) som man kan söka i här http://search.maven.org/. Det går givetvis att konfigurerar upp andra externa repositoryn men som vänligt gäller konvention över konfiguration om inget annat sägs.

Artefakter

De resurser som förvaras i ett Maven-repository kallas för artefakter och alla dina projekt bygger också artefakter. Alla Maven-projekt måste ha en generell benämning som gör att den går att lokalisera i ett repository. Notationen för att peka ut (koordinaten för) en specifik artefakt är följande:

groupId - pekar ut en logisk gruppering i vilken artefakten hör hemma, t.ex. se.chilmers.mysystem (jmfr. XML namespace eller java-package) artifactId - namnet på artefakten t.ex. mysystem-search-services version - versionen av artefakten t.ex. 1.0.0 (se mer om versioner nedan)

Ett beroende kan således deklareras på följande sätt i pom.xml

<dependencies>
    <dependency>
        <groupId>org.apache.poi</groupId>
        <artifactId>poi</artifactId>
        <version>3.8</version>
    </dependency>
    ... övriga dependencies ...
</dependencies>

Då vi lägger en deklaration som ovan i vår pom.xml så vet vi att vi får med oss allt vi behöver för att kunna använda version 3.8 av Apache POI.

Transitiva beroenden

Med deklarationen avsnittet ovan så vet vi att vi får med oss Apache POI och även eventuella transitiva beroenden som den behöver för att fungera. Det betyder att om en artefakt vi är beroende av, i sin tur är beroende av andra artefakter så får vi med dem också automatiskt i bygget. Dessa kallas då transitiva beroenden.

Versioner

Alla artefakter i ett Maven-repository har en viss version t.ex. 1.0.0. Enligt dokumentationen för Versions Maven plugin så är den officiella syntaxen för versionering följande:

<MajorVersion [> . <MinorVersion [> . <IncrementalVersion ] ] [> - <BuildNumber | Qualifier ]>

Där vi normalt klarar oss med två eller tre siffror d.v.s. 1.0 alternativt 1.0.0. När man väl har installerat eller iaf när man deployat en version på ett fjärr-repository så bör man inte ändra på den versionen. Det vill säga version 1.0.0 får inte förändras då den en gång har existerat. För att detta inte skall bli ohållbart så har man något som kallas för SNAPSHOT-releaser som är ett rörligt mål. Man låter alltså en artefakt vara i en SNAPSHOT-release tills dess att man är redo att släppa en riktig version av artefakten. Under tiden man utvecklar sin 1.0.0-version så har man alltså versionen

<version>1.0.0-SNAPSHOT</version>

Av den anledningen att SNAPSHOT-releaser kan ändra sig så bör man aldrig låta sitt system i en skarp release vara beroende av SNAPSHOT-versioner. Det är dock som sagt mycket behändigt att utnyttja under utveckling av en release

Scope

Lite överkurs men man kan också välja om man endast vill ha ett beroende i ett visst scope, t.ex. endast vid kompilering, endast i runtime eller (vanligast) endast vid test-exekvering. Det kan till exempel vara något som du behöver för att kompilera men som du vet redan finns i den målmiljö där du installerar paketet. Det kan också vara att man använder ett visst test-ramverk för enhetstestning som man inte vill packa med i sin installationsfil eftersom det endast används vid tester i samband med bygge. T.ex. så vill man endast ha JUnit vid enhetstestning på detta vis:

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

Projektstruktur

För att det skall fungera att arbeta med ett bygge deklarativt och med konvention över konfiguration så krävs en viss struktur. Maven har således en konvention för hur filer skall placeras i ett bygge. Konventionen går givetvis att överrida genom att lägga till egen konfiguration för detta men det är inte att rekommendera. i de flesta fall.

Så här ser grundstrukturen ut i ett Maven-projekt

./pom.xml Byggfilen som innehåller byggets deklarationer samt konfiguration
./src/main Innehåller kod och resurser för huvudbygget, det som skall med vid bygge av artefakten (t.ex. jar-filen)
./src/main/java Innehåller kod för huvudbygget, det är här man lägger sin Java-kod i lämpliga paketnamn. T.ex. ./src/main/java/se/chilmers/mysystem/parsing/XmlParser.java
./src/main/resources Innehåller resurser för huvudbygget. De resurser man lägger här kommer att byggas med och vara tillgängliga på classpathen. Det vill säga att klassladdaren kommer att läsa in dem som resurser. Resurser som kan vara intressanta att ha här är sådana som kan behövas i "runtime" t.ex. programkonfigurations-filer (om man kan tänka sig att bygga om för varje konfigurations-ändring), loggkonfigurations-filer,localization-filer (l10n) och internationalization-filer (i18n), det vill säga språkfiler, xml-scheman och andra typer av resurser som kan vara bra att ha med sig i runtime.
./src/test Innehåller kod och resurser för test. Maven kör enligt konvention automatiskt unit-tester i samband med bygge. Kod och resurser för dessa tester läggs här. Inget som ligger i den här foldern kommer (default) med vid bygget av artefakten (.jar, .war etc) då dessa används endast då man kör testerna.
./src/test/java Innehåller kod för unit-tester. Alla JUnit-tester som Maven hittar i den här foldern kommer att köras automatiskt vid bygge. På det viset för man direkt feedback på om man har haft sönder något viktigt sedan senaste bygget. Det är därför viktigt att man ser till att ha tester för sina viktigaste funktioner så att man direkt ser om man har påverkat kärnfunktionaliteten. Kallas även regressions-testning. Se exempel på exmpel på ett JUnit-test på [testnings-sidan](Testning).
./src/test/resources Innehåller resurser för test, till exempel logg-konfiguration, test-datafiler med mera.
./target Här hamnar allt som byggs vid ett bygge. Allt som finns här skall vara återproducerbart genom att bygga igen. Man vill således väldigt sällan spara target-foldern i versionshanteringssytem och dylikt.

Mavens bygg-livscykel

Den största byggstenen i Mavens bygg-livscykel heter faser och konventionen för dess ordning/default-livscykelns ordning är (översatt från http://maven.apache.org/guides/introduction/introduction-to-the-lifecycle.html som beskriver Mavens bygglivscykel i sin helhet):

* validate - Validerar att projektet är korrekt och att all nödvändig information finns tillgänglig.
* compile - Kompilerar källkoden för projektet
* test - Testar den kompilerade koden med ett lämpligt enhets-testramverk. Dessa tester bör inte kräva att koden är packad eller finns i ett repository.
* package - Ta den kompilerade koden och paketera den i sitt distributionsformat, t.ex. en JAR-fil.
* integration-test - Hantera och, om nödvändigt, installera paketet i en miljö där integrationstester kan köras.
* verify - Kör eventuella kontroller för att verifiera att paketet är giltigt (valid) och möter kvalitetskriterier.
* install - Installerar paketet till det lokala repositoryt, för att använda som beroende i andra projekt lokalt.
* deploy - Görs i en integrations- eller release-miljö. Kopierar det färdiga paketet till ett fjärr-repository för att dela med andra utvecklare eller projekt.

Mavens kommandorad

Maven körs på kommandoraden med kommandot mvn.

mvn clean - Rensar allt som är byggt i projektet (allt under target-foldern)

mvn install - Kör allting framm till och med install-fasen (se i tabellen ovan).

mvn clean install - Man kan också kombinera clean med en fas. Detta är det kommando som jag normalt använder vi bygge då den börjar från ett rent projekt och också installerar bygget i det lokala repositoryt efteråt.

mvn test - Som ni säkert listat ut kan man även använda andra faser än install, till exempel om man bara vill kompilera och köra testerna.

Maven i Eclipse

Från och med Eclipse Indigo som släpptes sommaren 2011 så är M2E (före detta M2 Eclipse) en officiell del av Eclipse. För att installera M2E så starta Eclipse, gå till Help-menyn -> Eclipse Marketplace... Sök på maven och klicka install vid Maven Integration for Eclipse och följ instruktionerna.

Det kan också vara intressant att installera Maven Integration for Eclipse WTP om du använder Eclipse WTP plugin i ditt arbete.

När du installerat din M2E så kan du välja att importera ett Maven-projekt via File-menyn -> Import... Välj Maven/Existing Maven Projects, och följ sedan instruktionerna för att slutföra importen.