вторник, 1 декабря 2009 г.

Apache Maven2 – средство для сборки проектов

В данной статье, я постараюсь описать основные возможности Apache Maven2 – средства которое значительно облегчает разработку, как простых проектов, так и сложных, многомодульных проектов над которыми работают несколько команд разработчиков.

Современная разработка программных средств все чаще требует сотрудничества различных команд и следовательно требует стандартизированного подхода к структуре проекта. Особенно это касается проектов ориентированных на open source сообщество. Все это требует использования нового поколения инструментов совместной разработки проектов, одним из которых является Apache Maven2.


Краткое содержание.
В этом посте попытаюсь пошагово описать следующие понятия:
  • Модель управления связями
  • Репозитарии «зависимостей»
  • «Архитипы» - шаблоны
  • Загрузка и установка Maven2
  • Структура файла проекта pom.xml
  • Первый проект в maven2
Основные понятия
Apache Maven2 – это средство при разработчики которого, попытались применить к модели проекта: упорядоченную инфраструктуру, производительность при сборке а также лучшие практики организации.

Для создания проектов в Maven2 необходимо рассмотреть следующий набор моделей:

Объектная модель проекта (POM) – файл метаданных pom.xml, декларативно описывающий части проекта.

Модель управления связями – часть файла pom.xml описывающая «зависимости» проекта от других проектов, а также репозитории сторонних компонентов.

Жизненный цикл и его фазы – данная модель описывает используемые плагины их взаимосвязи а также фазы последовательность сборки проекта.


Модель управления связями
Модель управления связями определена в pom.xml файле в элементах (связи) и описывает все необходимые для сборки компоненты и библиотеки кода, которые в свою очередь хранятся на репозиторных серверах (или репозитории в контексте Maven2).
При сборке проекта Maven2 пытается определить связи в следующем порядке:


  1. Локальный репозиторий – обычно располагается в папке /.m2/repository
  2. Удаленные репозитории – репозитории сторонних производителей
  3. В случае невозможности определить связь выводится сообщение об ошибке.


По умолчанию для загрузки зависимостей используется глобальный всемирно доступный репозиторий Maven2, содержащий артефакты к самым распространенным проектам с открытым исходным кодом.

Список удаленных репозитариев по умолчанию содержится в файле /.m2/settings.xml См. Руководство по настройке Maven для получения подробной информации по настраиваемым опциям.


Пример описания зависимости в pom.xml файле:


<dependencies>
   <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>3.8.1</version>
   </dependency>
</dependencies>

 Где

groupId: Объект или организация, ответственная за производство артефакта. Например, net.alexhustas.examples может быть ID группы.

artifactId: Имя данного артефакта. Например, проект с основным классом OpsImp может использовать OpsImp как ID артефакта.

version: Номер версии артефакта. Поддерживается форма записи формата mmm.nnn.bbb-qqqqqqq-dd , где mmm - это основной номер версии, nnn - это дополнительный номер версии, и bbb - это уровень коррекции ошибок. Необязательными являются поля qqqqq (спецификатор) и dd (номер сборки).


Репозитарии «зависимостей»

Репозитории Maven 2 содержат набор артефактов, используемых Maven 2 для построения связей в проекте.

Артефакт упакован как файл JAR (WAR, EAR, ZIP), содержащий двоичную библиотеку или исполняемый код.

По сути репозиторий это деревья каталогов которые обычно представлены в следующем формате. См рисунок 1.


Рисунок 1.
Как видно на рисунке Maven2 содержит файлы POM артефактов вместе с хэшами контрольной суммы как для артефакта, так и для его POM в репозитории. Эти файлы гарантируют целостность артефакта, при его передаче между репозиториями.
Пример описания репозитория в pom.xml файле:

<repositories>
        <repository>
            <id>central</id>
            <url>http://repo1.maven.org/maven2</url>
        </repository>
    </repositories>

Где

id – Идентификатор репозитория.
url - Путь к удаленному репозиторию.
«Архитипы» - шаблоны
Вкратце archetype – это своего рода шаблон для формирования maven2 проекта.
Формат его использования таков:

mvn archetype:create -DarchetypeGroupId=org.apache.maven.archetypes -DgroupId=net.alexhustas.mavensimpleproject -DartifactId=mavenSimpleProject

В данном случае мы используем шаблон (archetype) для создания простого проекта.
Чтобы получить список доступных шаблонов надо выпонить следующую команду:

mvn archetype:generate

Результатом ее выполнения будет список доступных шаблонов:

[INFO] Scanning for projects...
[INFO] Searching repository for plugin with prefix: 'archetype'.
[INFO] ------------------------------------------------------------------------
[INFO] Building Maven Default Project
[INFO]    task-segment: [archetype:generate] (aggregator-style)
[INFO] ------------------------------------------------------------------------
[INFO] Preparing archetype:generate
[INFO] No goals needed for project - skipping
[INFO] Setting property: classpath.resource.loader.class => 'org.codehaus.plexus.velocity.ContextClassLoaderResourceLoader'.
[INFO] Setting property: velocimacro.messages.on => 'false'.
[INFO] Setting property: resource.loader => 'classpath'.
[INFO] Setting property: resource.manager.logwhenfound => 'false'.
[INFO] [archetype:generate]
[INFO] Generating project in Interactive mode
[INFO] No archetype defined. Using maven-archetype-quickstart (org.apache.maven.archetypes:maven-archetype-quickstart:1.0)
Choose archetype:
1: internal -> appfuse-basic-jsf (AppFuse archetype for creating a web application with Hibernate, Spring and JSF)
2: internal -> appfuse-basic-spring (AppFuse archetype for creating a web application with Hibernate, Spring and Spring MVC)
3: internal -> appfuse-basic-struts (AppFuse archetype for creating a web application with Hibernate, Spring and Struts 2)
4: internal -> appfuse-basic-tapestry (AppFuse archetype for creating a web application with Hibernate, Spring and Tapestry 4)
5: internal -> appfuse-core (AppFuse archetype for creating a jar application with Hibernate and Spring and XFire)
6: internal -> appfuse-modular-jsf (AppFuse archetype for creating a modular application with Hibernate, Spring and JSF)
7: internal -> appfuse-modular-spring (AppFuse archetype for creating a modular application with Hibernate, Spring and Spring MVC)
8: internal -> appfuse-modular-struts (AppFuse archetype for creating a modular application with Hibernate, Spring and Struts 2)
9: internal -> appfuse-modular-tapestry (AppFuse archetype for creating a modular application with Hibernate, Spring and Tapestry 4)
10: internal -> maven-archetype-j2ee-simple (A simple J2EE Java application)
11: internal -> maven-archetype-marmalade-mojo (A Maven plugin development project using marmalade)
12: internal -> maven-archetype-mojo (A Maven Java plugin development project)
13: internal -> maven-archetype-portlet (A simple portlet application)
14: internal -> maven-archetype-profiles ()
15: internal -> maven-archetype-quickstart ()
16: internal -> maven-archetype-site-simple (A simple site generation project)
17: internal -> maven-archetype-site (A more complex site project)
18: internal -> maven-archetype-webapp (A simple Java web application)
19: internal -> jini-service-archetype (Archetype for Jini service project creation)
20: internal -> softeu-archetype-seam (JSF+Facelets+Seam Archetype)
21: internal -> softeu-archetype-seam-simple (JSF+Facelets+Seam (no persistence) Archetype)
22: internal -> softeu-archetype-jsf (JSF+Facelets Archetype)
23: internal -> jpa-maven-archetype (JPA application)
24: internal -> spring-osgi-bundle-archetype (Spring-OSGi archetype)
25: internal -> confluence-plugin-archetype (Atlassian Confluence plugin archetype)
26: internal -> jira-plugin-archetype (Atlassian JIRA plugin archetype)
27: internal -> maven-archetype-har (Hibernate Archive)
28: internal -> maven-archetype-sar (JBoss Service Archive)
29: internal -> wicket-archetype-quickstart (A simple Apache Wicket project)
30: internal -> scala-archetype-simple (A simple scala project)
31: internal -> lift-archetype-blank (A blank/empty liftweb project)
32: internal -> lift-archetype-basic (The basic (liftweb) project)
33: internal -> cocoon-22-archetype-block-plain ([http://cocoon.apache.org/2.2/maven-plugins/])
34: internal -> cocoon-22-archetype-block ([http://cocoon.apache.org/2.2/maven-plugins/])
35: internal -> cocoon-22-archetype-webapp ([http://cocoon.apache.org/2.2/maven-plugins/])
36: internal -> myfaces-archetype-helloworld (A simple archetype using MyFaces)
37: internal -> myfaces-archetype-helloworld-facelets (A simple archetype using MyFaces and facelets)
38: internal -> myfaces-archetype-trinidad (A simple archetype using Myfaces and Trinidad)
39: internal -> myfaces-archetype-jsfcomponents (A simple archetype for create custom JSF components using MyFaces)
40: internal -> gmaven-archetype-basic (Groovy basic archetype)
41: internal -> gmaven-archetype-mojo (Groovy mojo archetype)
Choose a number:  (1/2/3/4/5/6/7/8/9/10/11/12/13/14/15/16/17/18/19/20/21/22/23/24/25/26/27/28/29/30/31/32/33/34/35/36/37/38/39/40/41) 15:


Загрузка и установка Maven2

Для установки maven2 необходимо:

  • Скачать последнюю версию дистрибутива с сайта http://maven.apache.org/download.html
  • Разархивировать дистрибутивы в рабочую папку maven2 (например /opt/maven2)
  • Добавить директорию, в которой распакован maven2, в переменную среды MAVEN_HOME
  • Добавить путь в переменную PATH= $MAVEN_HOME/bin:$PATH
Чтобы проверить правильность установки, наберите команду mvn -help. В консоле появится следующее сообщение

C:\>mvn -help
 
синтаксис: mvn [options] [<goal(s)>] [
<phase(s)>]
 
Опции:
 -C,--strict-checksums  построение не выполняется, если контрольные суммы не совпадают
 -c,--lax-checksums  выводит предупреждение, если контрольные суммы не совпадают
 -P,--activate-profiles  список параметров для активации;
    в качестве разделителей используются запятые
 -ff,--fail-fast  прекращает при первом сбое в реакторизованном построении
 -fae,--fail-at-end  не выполняет все созданное позже;
    позволяет продолжить все незатронутые построения
 -B,--batch-mode  выполняет в не-интерактивном (пакетном) режиме
 -fn,--fail-never  НИКОГДА не нарушает построение, вне зависимости от результатов проекта
 -up,--update-plugins  синоним для cpu
 -N,--non-recursive  не вызывать рекурсивно в под-проектах
 -npr,--no-plugin-registry не использовать ~/.m2/plugin-registry.xml
    для версии плагинов
 -U,--update-snapshots  обновить все состояния памяти
    вне зависимости от распределения ресурсов репозитория
 -cpu,--check-plugin-updates выполнить принудительную проверку обновления
    любых необходимых зарегистрированных плагинов
 -npu,--no-plugin-updates прекратить проверку обновления
    любых необходимых зарегистрированных плагинов
 -D,--define   определить системное свойство
 -X,--debug   вывести выходные данные выполнения отладки
 -e,--errors   вывести сообщения об ошибках при выполнении
 -f,--file   принудительно использовать альтернативный файл POM.
 -h,--help   вывести справочную информацию
 -o,--offline   работать в режиме офлайн
 -r,--reactor   выполнить задачи проекта, найденные в реакторе
 -s,--settings   альтернативный путь для файла установок пользователя
 -v,--version   вывести информацию о версии


Структура файла проекта pom.xml

И так, рассмотрим теперь конфигурационный файл проекта pom.xml детально. Для начала я приведу пример простой конфигурации.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
<?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/maven-v4_0_0.xsd">
 <modelVersion>4.0.0</modelVersion>
 <groupId>net.alexhustas.mavensimpleproject</groupId>
 <artifactId>mavenSimpleProject</artifactId>
<packaging>jar</packaging>
 <version>1.0-SNAPSHOT</version>
 <name>mavenSimpleProject</name>
 <url>http://maven.apache.org</url>
 <build>
<plugins>
<plugin>
    <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>junit</groupId>
   <artifactId>junit</artifactId>
   <version>3.8.1</version>
   <scope>test</scope>
  </dependency>
 </dependencies>
 <repositories>
  <repository>
   <id>central</id>
   <url>http://repo1.maven.org/maven2</url>
  </repository>
 </repositories>
</project>


Теперь рассмотрим файл по секциям:

В секции

3
4
5
6
7
8
9
<modelVersion>4.0.0</modelVersion>
 <groupId>net.alexhustas.mavensimpleproject</groupId>
 <artifactId>mavenSimpleProject</artifactId>
<packaging>jar</packaging>
 <version>1.0-SNAPSHOT</version>
 <name>mavenSimpleProject</name>
 <url>http://alexhustas.net</url>

Представлена общая информация о проекте

modelVersion – версия используемой модели

groupId - ID ответственного лица (обычно представляется в виде пути к пакету)

artifactId - Имя артефакта (например название проекта)

packaging - способ «пакования» проекта (jar, war, ear)

version - версия сборки проекта

name - название проекта

url - Адрес проекта в интернет



Секция build описывает процесс сборки

10
11
12
13
14
15
16
17
18
19
20
21
<build>
<plugins>
<plugin>
    <artifactId>maven-compiler-plugin</artifactId>
    <version>2.0.2</version>
    <configuration>
     <source>1.5</source>
     <target>1.5</target>
    </configuration>
   </plugin>
  </plugins>
 </build>

В данном случае мы подключили плагин для компиляции java кода версии 1.5
В следующей секции описывается все зависимости проекта

22
23
24
25
26
27
28
29
<dependencies>
  <dependency>
   <groupId>junit</groupId>
   <artifactId>junit</artifactId>
   <version>3.8.1</version>
   <scope>test</scope>
  </dependency>
 </dependencies>


Как видно из кода указан groupId и artifactId подключаемой зависимости. Подключаемая зависимость будет загружаться из репозиториев, сначала будет произведен поиск в локальном репозитории затем в глобальном репозитории и в репозиториях указанных в следующей секции.

30
31
32
33
34
35
<repositories>
  <repository>
   <id>central</id>
   <url>http://repo1.maven.org/maven2</url>
  </repository>
</repositories>


В данном случае подключается основной глобальный репозиторий, который используется по умолчанию и здесь указан для примера.

Для более детального изучения формата pom.xml файла можно обратиться к официальной документации - http://maven.apache.org/guides


Первый проект в maven2

Теперь давайте попробуем создать наш первый проект.
В командной строке выполните следующую команду:

mvn archetype:create -DarchetypeGroupId=org.apache.maven.archetypes -DgroupId=net.alexhustas.mavensimpleproject -DartifactId=mavenSimpleProject


После выполнения на экране появится сообщение об успешном создании проекта


…
INFO] ------------------------------------------------------------------------
INFO] BUILD SUCCESSFUL
INFO] ------------------------------------------------------------------------
INFO] Total time: 2 seconds
INFO] Finished at: Thu Aug 27 09:36:26 GMT+06:00 2009
INFO] Final Memory: 8M/14M
INFO] ------------------------------------------------------------------------

Рисунок 2.

Созданный проект будет иметь следующую структуру каталогов см рисунок 2.

В каталоге src/main/java – содержатся все наши исходные коды java классов. По умолчанию maven2 сгенерировал класс-пример

1
2
3
4
5
6
7
8
9
10
11
12
13
package net.alexhustas.mavensimpleproject;
 
/**
 * Hello world!
 *
 */
public class App
{
    public static void main( String[] args )
    {
        System.out.println( "Hello World!" );
    }
}

В каталоге src/test/java - находятся все JUnit тесты нашего проекта. Maven2 сгенерировал класс-пример теста для net.alexhustas.mavensimpleproject.App

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
package net.alexhustas.mavensimpleproject;
 
import junit.framework.Test;
import junit.framework.TestCase;
import junit.framework.TestSuite;
 
/**
 * Unit test for simple App.
 */
public class AppTest
    extends TestCase
{
    /**
     * Create the test case
     *
     * @param testName name of the test case
     */
    public AppTest( String testName )
    {
        super( testName );
    }
 
    /**
     * @return the suite of tests being tested
     */
    public static Test suite()
    {
        return new TestSuite( AppTest.class );
    }
 
    /**
     * Rigourous Test :-)
     */
    public void testApp()
    {
        assertTrue( true );
    }
}

Теперь можно скомпилировать проект с помощью команды

mvn compile

На экране должно появится сообщение о удачной компиляции

[INFO] Compiling 1 source file to /home/alex/mavenprojects/mavenSimpleProject/target/classes
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESSFUL
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 3 seconds
[INFO] Finished at: Thu Aug 27 09:49:24 GMT+06:00 2009
[INFO] Final Memory: 8M/14M
[INFO] ------------------------------------------------------------------------

Все скомпилированные фалы содержатся в папке /target/classes

Для запуска процесса тестирования необходимо выплнить следующую команду:

mvn test

Но предварительно необходимо изменить тест добавив следующий код:

31
32
33
34
35
36
37
/**
     * Rigourous Test :-)
     */
    public void testApp()
    {
        App.main(null);
    }

Теперь после выполнения теста на экране можно увидеть следующее сообщение

-------------------------------------------------------
 T E S T S
-------------------------------------------------------
Running net.alexhustas.mavensimpleproject.AppTest
Hello World!
Tests run: 1, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.046 sec
 
Results :
 
Tests run: 1, Failures: 0, Errors: 0, Skipped: 0
 
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESSFUL
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 3 seconds
[INFO] Finished at: Thu Aug 27 09:55:12 GMT+06:00 2009
[INFO] Final Memory: 8M/16M
[INFO] ------------------------------------------------------------------------


На этом пожалуй можно завершить вводный пост. В следующем посте я планирую описать процесс использования IDE Eclipse совместно с Maven2.


Ресурсы


Комментариев нет: