Maven

Z FI WIKI
Přejít na: navigace, hledání

Maven je nástroj pro správu, řízení a automatizaci buildů aplikací.

Je to mocný nástroj. Z našeho pohledu jsou jeho hlavní výhody tyto:

  • jeho formát projektu je akceptován všemi vývojovými prostředími (IntelliJ IDEA, Eclipse, NetBeans)
  • poskytuje repository obsahující víceméně všechny javové knihovny ve všech verzích, mnoho z nich včetně zdrojáků a javadocu
  • v základním nastavení nás nutí dodržovat osvědčené konvence a postupy

Výhoda univerzálního formátu projektu je zřejmá, můžeme používat libovolné vývojové prostředí, nebo třeba editor vi a příkazový řádek, formát projektu je stále tentýž.

Repository nás zbavuje nutnosti starat se o knihovny a jejich požadavky, protože v repository má každá knihovna uvedeny i další knihovny, na kterých závisí.

Maven má přednastaveny postupy, které se v praxi osvědčily. Takže například odděluje zdrojové kódy tříd (ty jsou v adresáři src/main/java) od zdrojových kódů unit testů (ty jsou v adresáři src/test/java), zvlášť má i ostatní soubory typu obrázky, konfigurační soubory, properties a podobně (ty jsou v adresáři src/main/resources).

Obvyklé operace jsou přednastaveny, takže např. příkazem mvn package dáme povel k zabalení výsledku projektu, což zahrnuje kompilaci, spuštění unit testů a zabalení do souboru JAR nebo WAR.

pom.xml

Každý projekt má svůj konfigurační soubor pom.xml (POM jako Project Object Model). Jeho minimální obsah pro reálný projekt vypadá nějak takto:

 
<?xml version="1.0" encoding="UTF-8"?>
<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>cz.muni.pv168.trpaslik</groupId>
    <artifactId>evidence</artifactId>
    <version>1.0-SNAPSHOT</version>
    <name>Evidence trpaslíků</name>
 
    <developers>
        <developer>
            <name>Martin Kuba</name>
            <email>makub@ics.muni.cz</email>
            <url>http://www.muni.cz/people/3988</url>
            <organization>ÚVT MU</organization>
        </developer>
    </developers>
 
    <licenses>
        <license>
            <name>Apache License, Version 2.0</name>
            <url>http://www.apache.org/licenses/LICENSE-2.0</url>
        </license>
    </licenses>
 
    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
        <maven.compiler.source>8</maven.compiler.source>
	<maven.compiler.target>8</maven.compiler.target>
        <exec.mainClass>cz.muni.fi.Main</exec.mainClass>
    </properties>
 
   
    <!-- libraries, search for more at http://search.maven.org/ -->
    <dependencies>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.12</version>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-api</artifactId>
            <version>1.7.24</version>
        </dependency>
    </dependencies>
 
</project>

Tento pom.xml obsahuje obecné informace (název projektu, autor, licence), nastavení pluginů (verze jazyka, javadoc), a knihovny, na kterých projekt závisí.

Například příkazem mvn javadoc:javadoc můžeme díky pluginu maven-javadoc-plugin vygenerovat dokumentaci, a to včetně odkazů na dokumentace použitého JDK a knihoven.

Příkazem mvn package spustíme sérii akcí - kompilaci, testy, zabalení - která vyprodukuje soubor JAR obsahující zkompilované třídy a případně další soubory (obrázky, properties soubory).

vynechání testů

Pokud chceme zkompilovat a zabalit projekt, ale nechceme provést unit testy, musíme nastavit property maven.test.skip na hodnotu true.

To můžeme udělat bud na příkazové řádce pomocí

mvn -Dmaven.test.skip=true package

nebo přímo v pom.xml pomocí

 
    <properties>
        <maven.test.skip>true</maven.test.skip>   
    </properties>

pluginy

Spuštění z příkazového řádku

Pomocí pluginu můžeme například spustit specifikovanou třídu:

 
            <!-- spustit třídu pomocí "mvn exec:java" -->
            <plugin>
                <groupId>org.codehaus.mojo</groupId>
                <artifactId>exec-maven-plugin</artifactId>
                <version>1.2.1</version>
                <configuration>
                    <mainClass>cz.muni.fi.Main</mainClass>
                    <arguments>
                        <argument>argument1</argument>
                    </arguments>
                </configuration>
            </plugin>

Alternativně lze do pom.xml pouze uvést

 
  <properties>
    <exec.mainClass>cz.muni.fi.Main</exec.mainClass>
  </properties>

a spustit mvn exec:java, nebo bez editace pom.xml přímo z příkazového řádku specifikovat hlavní třídu:

mvn exec:java -Dexec.mainClass="cz.muni.fi.Main"

Spuštění webové aplikace v embedded Tomcatu 7

Plugin tomcat7-maven-plugin není od roku 2013 udržovaný. Do pom.xml přidat:

 
  <build>
    <plugins>
      <plugin>
        <groupId>org.apache.tomcat.maven</groupId>
        <artifactId>tomcat7-maven-plugin</artifactId>
        <version>2.2</version>
        <configuration>
          <path>/my-context-path</path>
        </configuration>
      </plugin>
    </plugins>
  </build>

a spustit mvn tomcat7:run.

Spuštění webové aplikace v embedded Tomcatu 8

Do pom.xml přidat:

 
  <properties>
    <tomcat.version>8.5.31</tomcat.version>
  </properties>
 
   <build>
    <plugins>
      <!-- embedded Tomcat 8 plugin configuration, use "mvn cargo:run" to run -->
      <plugin>
        <groupId>org.codehaus.cargo</groupId>
        <artifactId>cargo-maven2-plugin</artifactId>
        <version>1.6.8</version>
        <configuration>
          <container>
            <containerId>tomcat8x</containerId>
            <artifactInstaller>
              <groupId>org.apache.tomcat</groupId>
              <artifactId>tomcat</artifactId>
              <version>${tomcat.version}</version>
            </artifactInstaller>
          </container>
        </configuration>
      </plugin>
    </plugins>
  </build>

a spustit mvn cargo:run.

Spuštění webové aplikace v embedded Tomcatu 9

Do pom.xml přidat:

 
  <properties>
    <tomcat.version>9.0.12</tomcat.version>
  </properties>
 
   <build>
    <plugins>
      <!-- embedded Tomcat 8 plugin configuration, use "mvn cargo:run" to run -->
      <plugin>
        <groupId>org.codehaus.cargo</groupId>
        <artifactId>cargo-maven2-plugin</artifactId>
        <version>1.7.0</version>
        <configuration>
          <container>
            <containerId>tomcat9x</containerId>
            <artifactInstaller>
              <groupId>org.apache.tomcat</groupId>
              <artifactId>tomcat</artifactId>
              <version>${tomcat.version}</version>
            </artifactInstaller>
          </container>
        </configuration>
      </plugin>
    </plugins>
  </build>

a spustit mvn cargo:run.

Javadoc

Pomocí javadoc pluginu můžeme ovlivnit, jak Maven vygeneruje referenční dokumentaci projektu příkazem mvn javadoc:javadoc. Například můžeme uvést odkaz na javadoc použitých knihoven, v ukázce níže je to odkaz na javadoc k Java Enterprise Edition 6.

 
           <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-javadoc-plugin</artifactId>
                <version>2.9</version>
                <configuration>
                    <detectLinks>true</detectLinks>
                    <links>
                        <link>http://docs.oracle.com/javaee/6/api/</link>
                    </links>
                </configuration>
            </plugin>

Repository

Stáhnutí artefaktu

Z příkazového řádku např MySQL JDBC driver verze 5.1.32:

mvn org.apache.maven.plugins:maven-dependency-plugin:2.8:get -Dartifact=mysql:mysql-connector-java:5.1.32

Soubor pak bude k nalezení v ~/.m2/repository/mysql/mysql-connector-java/5.1.32/mysql-connector-java-5.1.32.jar

Prohledávat centrální repository lze na http://search.maven.org/

Lokální repository

Pokud potřebujeme v projektu použít knihovnu, která není v žádné Mavenové repository, můžeme si vytvořit lokální repository přímo v adresáři projektu.

Např. knihovna EAP FITS není v žádné repository, můžeme vytvořit repository v pracovním adresáři a přidat knihovnu skriptem

# downloads EAP FITS library and creates local Maven repository for it
wget http://swift.gsfc.nasa.gov/sdc/java/fits1.3.jar
wget http://swift.gsfc.nasa.gov/sdc/software/java/fits1.3/fits1.3_source.jar
mkdir local-repo
mvn deploy:deploy-file -Dfile=fits1.3.jar -Dsources=fits1.3_source.jar \
     -DgroupId=eap.fits -DartifactId=fits -Dversion=1.3 -Dpackaging=jar  \
     -Durl=file://$PWD/local-repo

rm fits1.3.jar fits1.3_source.jar
 

a pak stačí v pom.xml mít uvedeno

 
    <repositories>
        <!-- local repository for libraries that are not Mavenized -->
        <repository>
            <id>my-local-repo</id>
            <url>file://${basedir}/local-repo</url>
        </repository>
    </repositories>
    <dependencies>
        <!-- EAP FITS -->
        <dependency>
            <groupId>eap.fits</groupId>
            <artifactId>fits</artifactId>
            <version>1.3</version>
        </dependency>
    </dependencies>

Závislosti mezi projekty

Obecně můžeme použít závislost jen na projektu, který byl již instalován do repository, ať už lokální nebo globální. Do repository se projekt dostane příkazem mvn install.

Pokud však vyvíjíme složitější projekt, můžeme ho rozdělit na více modulů, které spojíme agregačním projektem. (Viz Maven multimodule).

Např. mějme dva moduly:

  • books-jdbc typu jar s implementací business logiky nad databází
  • books-web typu war s webovým rozhraním nad touto logikou.

K nim pak vytvoříme agregační projekt books-app typu pom, všechny s adresáři vedle sebe:

 books-jdbc/pom.xml
 books-web/pom.xml
 books-app/pom.xml

kde v books-jdbc/pom.xml je

 
<project ...>
    <modelVersion>4.0.0</modelVersion>
    <groupId>cz.muni.fi.pv168</groupId>
    <artifactId>books-jdbc</artifactId>
    <version>1.0</version>
    <packaging>jar</packaging>
    <name>Books business logic in JDBC</name>

a v books-web/pom.xml je uvedeno

 
<project ...>
    <modelVersion>4.0.0</modelVersion>
    <groupId>cz.muni.fi.pv168</groupId>
    <artifactId>books-web</artifactId>
    <version>1.0</version>
    <packaging>war</packaging>
    <name>Books web interface</name>

a v agregačním projektu je v books-app/pom.xml uvedeno:

 
<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>cz.muni.fi.pv168</groupId>
    <artifactId>books-app</artifactId>
    <version>1.0</version>
    <packaging>pom</packaging>
    <name>Books aggregator module</name>
 
    <modules>
     <module>../books-jdbc</module>
     <module>../books-web</module>
    </modules>
 
</project>

Pak příkazy použité na agregační modul se propagují do ostatních modulů, tj. můžeme udělat třeba mvn clean nebo mvn package jen v něm, a příkazy se provedou i v ostatních modulech.