Статьи

Инструменты сборки Java: Ant против Maven против Gradle

В начале был Make как единственный доступный инструмент для сборки. Позже это было улучшено с GNU Make . Однако с тех пор наши потребности возросли, и, как следствие, эволюционировали инструменты для сборки.

В экосистеме JVM доминируют три инструмента сборки:

Муравей с плющом

муравей Ant был первым среди «современных» инструментов сборки. Во многих отношениях он похож на Make. Он был выпущен в 2000 году и за короткий промежуток времени стал самым популярным инструментом сборки для Java-проектов. Он имеет очень низкую кривую обучения, что позволяет любому начать использовать его без какой-либо специальной подготовки. Он основан на идее процедурного программирования.

После первоначального выпуска он был улучшен возможностью принимать плагины.

Основным недостатком был XML как формат для написания скриптов сборки. XML, будучи по своей природе иерархическим, не очень подходит для процедурного подхода к программированию, который использует Ant. Другая проблема с Ant состоит в том, что его XML имеет тенденцию становиться неуправляемо большим при использовании со всеми проектами, кроме очень маленьких.

Позже, когда управление зависимостями по сети стало необходимостью, Ant принял Apache Ivy .

Основным преимуществом Ant является его контроль над процессом сборки.

специалист

специалист Maven был выпущен в 2004 году. Его целью было улучшить некоторые проблемы, с которыми сталкиваются разработчики при использовании Ant.

Maven продолжает использовать XML в качестве формата для написания спецификации сборки. Однако структура диаметрально отличается. В то время как Ant требует от разработчиков написания всех команд, которые приводят к успешному выполнению какой-либо задачи, Maven опирается на соглашения и предоставляет доступные цели (цели), которые могут быть вызваны. В качестве дополнительного, и, вероятно, наиболее важного дополнения, Maven представил возможность загрузки зависимостей по сети (позже принятую Ant через Ivy). Это само по себе революционизировало способ поставки программного обеспечения.

Однако у Maven есть свои проблемы. Управление зависимостями плохо обрабатывает конфликты между разными версиями одной и той же библиотеки (в этом Айви гораздо лучше). XML как формат конфигурации сборки строго структурирован и стандартизирован. Настройка целей (целей) сложно. Поскольку Maven сфокусирован в основном на управлении зависимостями, сложные, настраиваемые сценарии сборки на самом деле труднее писать в Maven, чем в Ant.

Конфигурация Maven, написанная на непрерывном XML, является большой и громоздкой. В больших проектах он может содержать сотни строк кода, не делая ничего «экстраординарного».

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

В то же время интерес к DSL (предметно-ориентированным языкам) продолжал расти. Идея состоит в том, чтобы иметь языки, предназначенные для решения проблем, относящихся к определенной области. В случае сборок одним из результатов применения DSL является Gradle.

Gradle

Gradle Gradle сочетает в себе хорошие части обоих инструментов и строит поверх них DSL и другие улучшения. Он обладает мощью и гибкостью Ant, а также жизненным циклом Maven и простотой использования. Конечным результатом является инструмент, который был выпущен в 2012 году и привлек много внимания за короткий период времени. Например, Google принял Gradle в качестве инструмента сборки по умолчанию для ОС Android.

Gradle не использует XML. Вместо этого у него был собственный DSL на основе Groovy (один из языков JVM). В результате скрипты сборки Gradle имеют тенденцию быть намного короче и понятнее, чем написанные для Ant или Maven. Объем стандартного кода намного меньше с Gradle, поскольку его DSL предназначен для решения конкретной проблемы: продвижение программного обеспечения через его жизненный цикл, от компиляции до статического анализа и тестирования до упаковки и развертывания.

Он использует Apache Ivy для JAR-зависимостей.

Усилие Gradle может быть суммировано как «условность хороша, как и гибкость».

Примеры кода

Мы создадим сценарии сборки, которые будут компилироваться, выполнять статический анализ, запускать модульные тесты и, наконец, создавать файлы JAR. Мы выполним эти операции во всех трех средах (Ant, Maven и Gradle) и сравним синтаксис. Сравнивая код для каждой задачи, мы сможем лучше понять различия и принять обоснованное решение относительно выбора инструмента для сборки.

Обо всем по порядку. Если вы сами сделаете примеры из этой статьи, вам понадобятся Ant , Ivy , Maven и Gradle . Пожалуйста, следуйте инструкциям по установке, предоставленным производителями этих инструментов. Вы можете не запускать примеры самостоятельно и вообще пропустить установку. Фрагментов кода должно быть достаточно, чтобы дать вам общее представление о том, как работает каждый из инструментов.

Репозиторий кода https://github.com/vfarcic/JavaBuildTools содержит код Java (два простых класса с соответствующими тестами), конфигурацию контрольного стиля и файлы конфигурации Ant, Ivy, Maven и Gradle.

Давайте начнем с Муравья и Айви.

Муравей с плющом

Зависимости плюща должны быть указаны в файле ivy.xml. Наш пример довольно прост и требует только зависимостей JUnit и Hamcrest.

[ ivy.xml ]

1
2
3
4
5
6
7
<ivy-module version="2.0">
    <info organisation="org.apache" module="java-build-tools"/>
    <dependencies>
        <dependency org="junit" name="junit" rev="4.11"/>
        <dependency org="org.hamcrest" name="hamcrest-all" rev="1.3"/>
    </dependencies>
</ivy-module>

Теперь мы создадим наш скрипт сборки Ant. Его задача будет состоять только в том, чтобы скомпилировать файл JAR. Конечным результатом является следующий build.xml.

[ build.xml ]

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
<project xmlns:ivy="antlib:org.apache.ivy.ant" name="java-build-tools" default="jar">
 
    <property name="src.dir" value="src"/>
    <property name="build.dir" value="build"/>
    <property name="classes.dir" value="${build.dir}/classes"/>
    <property name="jar.dir" value="${build.dir}/jar"/>
    <property name="lib.dir" value="lib" />
    <path id="lib.path.id">
        <fileset dir="${lib.dir}" />
    </path>
 
    <target name="resolve">
        <ivy:retrieve />
    </target>
 
    <target name="clean">
        <delete dir="${build.dir}"/>
    </target>
 
    <target name="compile" depends="resolve">
        <mkdir dir="${classes.dir}"/>
        <javac srcdir="${src.dir}" destdir="${classes.dir}" classpathref="lib.path.id"/>
    </target>
 
    <target name="jar" depends="compile">
        <mkdir dir="${jar.dir}"/>
        <jar destfile="${jar.dir}/${ant.project.name}.jar" basedir="${classes.dir}"/>
    </target>
 
</project>

Сначала мы указываем несколько свойств. С этого момента это одно задание за другим. Мы используем Ivy для разрешения зависимостей, очистки, компиляции и, наконец, создания файла JAR. Это довольно много настроек для задачи, которую должен выполнить почти каждый Java-проект.

Чтобы запустить задачу Ant, которая создает файл JAR, выполните следующее.

1
ant jar

Посмотрим, как бы Maven выполнял такой же набор задач.

специалист

[ pom.xml ]

01
02
03
04
05
06
07
08
09
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
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
 
 
    <modelVersion>4.0.0</modelVersion>
    <groupId>com.technologyconversations</groupId>
    <artifactId>java-build-tools</artifactId>
    <packaging>jar</packaging>
    <version>1.0</version>
 
    <dependencies>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.11</version>
        </dependency>
        <dependency>
            <groupId>org.hamcrest</groupId>
            <artifactId>hamcrest-all</artifactId>
            <version>1.3</version>
        </dependency>
    </dependencies>
 
    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>2.3.2</version>
            </plugin>
        </plugins>
    </build>
 
</project>

Чтобы запустить цель Maven, которая создает файл JAR, выполните следующее.

1
mvn package

Основное отличие состоит в том, что с Maven нам не нужно указывать, что делать. Мы не создаем задачи, а устанавливаем параметры (каковы зависимости, какие плагины использовать…). Это показывает основное различие между Муравьем и Мавеном. Позже продвигает использование соглашений и предоставляет цели (цели) из коробки. XML-файлы Ant и Maven имеют тенденцию расти со временем. Чтобы проиллюстрировать это, добавим плагины Maven CheckStyle, FindBugs и PMD, которые будут заниматься статическим анализом. Все три являются достаточно стандартными инструментами, используемыми в той или иной форме во многих проектах Java. Мы хотим, чтобы весь статический анализ выполнялся как часть единой целевой проверки вместе с модульными тестами. Кроме того, мы должны указать путь к пользовательской конфигурации контрольного стиля и убедиться, что он не работает в случае ошибки. Дополнительный код Maven следующий:

[ pom.xml ]

01
02
03
04
05
06
07
08
09
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
<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-checkstyle-plugin</artifactId>
    <version>2.12.1</version>
    <executions>
        <execution>
            <configuration>
                <configLocation>config/checkstyle/checkstyle.xml</configLocation>
                <consoleOutput>true</consoleOutput>
                <failsOnError>true</failsOnError>
            </configuration>
            <goals>
                <goal>check</goal>
            </goals>
        </execution>
    </executions>
</plugin>
<plugin>
    <groupId>org.codehaus.mojo</groupId>
    <artifactId>findbugs-maven-plugin</artifactId>
    <version>2.5.4</version>
    <executions>
        <execution>
            <goals>
                <goal>check</goal>
            </goals>
        </execution>
    </executions>
</plugin>
<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-pmd-plugin</artifactId>
    <version>3.1</version>
    <executions>
        <execution>
            <goals>
                <goal>check</goal>
            </goals>
        </execution>
    </executions>
</plugin>

Чтобы выполнить цель Maven, которая запускает как модульные тесты, так и статический анализ с CheckStyle, FindBugs и PMD, выполните следующее.

1
mvn verify

Нам пришлось написать много XML, который выполняет очень простой и часто используемый набор задач. В реальных проектах с гораздо большим количеством зависимостей и задач файлы Maven pom.xml могут легко достигать сотен или даже тысяч строк XML.

Вот как это выглядит в Gradle.

Gradle

[ build.gradle ]

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
apply plugin: 'java'
apply plugin: 'checkstyle'
apply plugin: 'findbugs'
apply plugin: 'pmd'
 
version = '1.0'
 
repositories {
    mavenCentral()
}
 
dependencies {
    testCompile group: 'junit', name: 'junit', version: '4.11'
    testCompile group: 'org.hamcrest', name: 'hamcrest-all', version: '1.3'
}

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

1
gradle tasks --all

Ясность, сложность и кривая обучения

Для новичков Муравей — самый ясный инструмент всего. Просто прочитав конфигурационный XML, можно понять, что он делает. Однако написание задач Ant легко становится очень сложным. У Maven и, особенно, Gradle есть много задач, уже доступных из коробки или через плагины. Например, увидев следующую строку, вероятно, тем, кто не посвящен в загадки Gradle, неясно, какие задачи будут разблокированы для использования нами.

[Build.gradle]

1
apply plugin: 'java'

Эта простая строка кода добавляет более 20 задач, ожидающих нас.

Читаемость муравья и простота Maven — это, на мой взгляд, ложные аргументы, которые применимы только во время короткой начальной кривой обучения Gradle. После использования Gradle DSL его синтаксис становится короче и проще для понимания, чем в Ant или Maven. Более того, только Gradle предлагает как соглашения, так и создание команд. Хотя Maven можно расширить с помощью задач Ant, он утомителен и не очень продуктивен. Gradle с Groovy выводит его на следующий уровень.

Следующая статья углубится в Gradle и более подробно объяснит его интеграцию с Groovy.

Ссылка: Инструменты сборки Java: Ant vs Maven vs Gradle от нашего партнера по JCG Виктора Фарсика из блога технологических бесед .