Как с помощью maven работать с библиотеками, которых в maven нет

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


Также я опишу, как сделать maven проект, который генерирует артефакт, по совместительству являющийся библиотекой, и как подключить эту библиотеку к другому своему же maven проекту.


Эта статья для тех, кто только начинает осваивать java.


image


В моей предыдущей статье было сказано, что maven сам скачает все указанные в pom.xml зависимости. А вот что будет, если он какую-нибудь зависимость не найдёт? В таком случае maven скажет, что зависимость не обнаружена и прервёт процесс сборки с ошибкой. Что делать в этом случае?


Этот вопрос, на самом деле, распадается на несколько вопросов, каждый из которых надо решать индивидуально. Выбор решения же определяется тем, где эта зависимость есть.


Зависимость может быть в интернете в каком-то месте, о существовании которого maven не знает. Ещё она может быть в виде jar файла у вас на руках и, наконец, в виде исходного кода, оформленного как maven проект.


Об этих трёх случаях мы и поговорим.


Но сначала надо коротко прояснить один вопрос.


Откуда maven качает библиотеки


На просторах интернета есть сервер, на котором выложены java библиотеки. Этот сервер называется репозиторием, а по-русски — хранилищем. Это не какой-то абстрактный, а вполне конкретный ресурс, адрес которого зашит в дефолтные настройки maven. Поэтому он называется репозиторием по умолчанию. Именно там maven будет искать зависимости из pom.xml.


Как быть, если библиотеки нет в удалённом хранилище по умолчанию, но она есть в другом удалённом хранилище


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


Причины проблемы немного разные, но решение одинаковое — нужно указать репозиторий, в котором зависимости есть. Это либо какой-то другой адрес в Интернете, либо адрес репозитория, поднятого админами в локальной сети.


Как указать maven проекту, где искать дополнительный репозиторий


Для того, чтобы указать maven, что зависимости надо искать не только в умолчальном репозитории, существует штатный механизм. Вот так можно прописать ещё один адрес для поиска.



    
      id репозитория
      адрес репозитория
    
 

Далее мы подключили репозиторий проекта Spring, в котором можно найти последние версии этого семейства бибилиотек. Вот как это выглядит внутри pom.xml



    com.springsource.repository.bundles.release 
    http://repository.springsource.com/maven/bundles/release 

Теперь maven, когда не найдёт зависимости в репозитории по умолчанию, или обнаружит, что оный недоступен — не запаникует, а поищет библиотеку в ещё одном репозитории и, если всё идёт по плану, найдёт её там.


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


Как подключить библиотеку, которой в репозиториях нет


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


Но, если это возможно, такую библиотеку лучше положить в проект и хранить прямо в системе контроля версий. Тогда библиотека будет доступна программе всегда и на любой машине, а шаг по копированию этой библиотеки в репозиторий можно не включать в мануал.


Для обработки таких кейсов у maven тоже есть штатный механизм. Только что мы выяснили, как указать maven удалённый репозиторий, отличный от умолчального. Так вот, не обязательно использовать удалённое хранилище. Можно сделать репозиторий в локальной файловой системе, положить туда библиотеку и проинструктировать maven искать зависимости ещё и там.


Как создать свой локальный репозиторий


Для этого, как сказано выше, у maven есть штатное средство.


Допустим у нас есть библиотека, которая находится в jar файле под названием hello-world-library-1.0-SNAPSHOT.jar. О библиотеке нам известно, что в ней есть один класс HelloWorld, который включает один статический метод say, печатающий в консоли, как несложно догадаться, Hello World.


Мы хотим в директории проекта создать директорию lib, в которой будет находиться наш дополнительный репозиторий, и поместить туда библиотеку. Для этого достаточно в директории проекта выполнить следующую команду.


mvn \
deploy:deploy-file \
-Durl=file:./lib \
-Dfile=hello-world-library-1.0-SNAPSHOT.jar \
-DgroupId=com.local \
-DartifactId=hello-world-library-local \
-Dpackaging=jar \
-Dversion=1.0-SNAPSHOT

Если вы используете операционную систему Windows, нужно заменить \ на ^, то есть написать


mvn ^
deploy:deploy-file ^
-Durl=file:./lib ^
-Dfile=hello-world-library-1.0-SNAPSHOT.jar ^
-DgroupId=com.local ^
-DartifactId=hello-world-library-local ^
-Dpackaging=jar ^
-Dversion=1.0-SNAPSHOT

Или можно просто убрать \ и написать команду в одну строчку.


mvn deploy:deploy-file -Durl=file:./lib -Dfile=hello-world-library-1.0-SNAPSHOT.jar -DgroupId=com.local -DartifactId=hello-world-library-local -Dpackaging=jar -Dversion=1.0-SNAPSHOT

Обратите внимание, как и для любого другого артефакта, для библиотеки нам нужно придумать groupId, artifactId и version. Мы потом укажем их в pom.xml, когда будем подключать зависимость.


Внутри директории, которую создаст команда, находится полноценный репозиторий, для использования которого достаточно указать maven, где он находится. Все сведения о том, какие библиотеки можно там найти, содержатся непосредственно в структуре директорий свежесозданного репозитория. Для последующего использования репозитория, например, на других машинах, команду deploy-file выполнять не надо.


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



    
        localrep
        local repository
        file:${project.basedir}/lib
    

Обратите внимание на пятую строку


file:${project.basedir}/lib

Тут сказано, что искать репозиторий надо в директории проекта, на которую указывает встроенная переменная maven project.basedir.


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


package com;

import static com.HelloWorld.say;

public class Application {
    public static void main(String[] argv) {
        say();
    }
}

Осталось добавить в pom.xml зависимость и можно собирать проект.




    4.0.0
    com
    library-user-with-local-repository
    1.0-SNAPSHOT

    
        
            localrep
            local repository
            file:${project.basedir}/lib
        
    

    
        
            com.local
            hello-world-library-local
            1.0-SNAPSHOT
        
    

Проверим:


mvn clean compile exec:java -Dexec.mainClass="com.Application"

Работает!


Директорию lib надо закомитить и библиотека будет доступна проекту вообще всегда.


Однако следует помнить об одном правиле.


Нужно обязательно обновлять номер версии библиотеки в локальном репозитории при каждом изменении jar файла


Maven воспринимает репозитории как внешние, поэтому, если не изменить номер версии, то maven будет использовать не версию библиотеки из директории lib, а ту, что он закешировал на локальной машине. В данном конкретном случае это не должно сыграть роли из-за суффикса SNAPSHOT, но об этом нужно знать.


Есть ещё один распространённый сценарий. У вас есть своя библиотека, которую вы сами собираете с помощью maven и потом подключаете к другому maven проекту.


Как сделать свою java библиотеку


Для того, чтобы сделать библиотеку, достаточно написать класс с модификатором public. И потом можно будет использовать этот класс в коде, к которому подключена библиотека.


Вот такой, например, класс.


package com;

public class HelloWorld {
    public static void say() {
        System.out.println("Hello world");
    }
}

Теперь нужно сделать maven проект, который будет собирать библиотеку, содержащую этот класс.


Как мы помним, с точки зрения maven, библиотека — это просто артефакт, поэтому помник будет выглядеть тривиально.




    4.0.0
    com
    hello-world-library
    1.0-SNAPSHOT

Итак, у нас есть класс со статическим методом, у нас есть описание артефакта для maven. Осталось только собрать этот код, чтобы получилась библиотека, то есть jar файл.


Просто напишем в консоли:


mvn package

После этого в директории target появится файл с названием \-\.jar, в нашем конткретном случае — hello-world-library-1.0-SNAPSHOT.jar, который и есть ваша библиотека.


Как подключить свежесозданную библиотеку к своему maven проекту


Для того, чтобы библиотеку потом можно было подключать к другому проекту, нужно вместо package написать install.


mvn install

Это нужно будет делать после каждого изменения в коде библиотеки, и на каждом компьютере, на котором мы захотим эту библиотеку использовать.


Теперь можно сделать новый проект, который будет использовать библиотеку.




    4.0.0
    com
    hello-world
    1.0-SNAPSHOT

    
        
            com
            hello-world-library
            1.0-SNAPSHOT
        
    

Внутри проекта будет один класс, который использует статический метод из библиотеки, чтобы сказать Hello world. Мы этот класс уже видели.


package com;

import static com.HelloWorld.say;

public class Application {
    public static void main(String[] argv) {
        say();
    }
}

Проверим ещё раз:


mvn compile exec:java -Dexec.mainClass="com.Application"

Работает не хуже предыдущего варианта!


Что если ваша библиотека использует другую библиотеку?


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


Сделаем библиотеку с непустыми зависимостями.




    4.0.0
    com
    hello-world-library
    1.0-SNAPSHOT

    
        
            org.apache.commons
            commons-lang3
            3.4
        
    


и напишем для неё код


package com;

import static org.apache.commons.lang3.ArrayUtils.*;

public class HelloWorld {
    public static void say() {
        String[] phrase = {"Hello"};
        phrase = add(phrase, " ");
        phrase = add(phrase, "world");
        for (String word : phrase) {
            System.out.print(word);
        }
        System.out.println();
    }
}

Теперь соберём её


mvn clean install

Перейдём в директорию с нашим проектом, который эту библиотеку использует и попробуем его собрать и запустить.


mvn clean compile exec:java -Dexec.mainClass="com.Application"

И работает!


Как это работает


Строго говоря знать, как процесс устроен внутри, не обязательно, но всё равно очень полезно.


Команда mvn install соберёт библиотеку, а потом положит её в локальный репозиторий по умолчанию. То есть в то же самое место, где лежат все библиотеки, которые вы когда-либо подключали к maven проектам, за исключением, разумеется, тех, которые находятся в локальных репозиториях, сделанных лично вами.


Потом, при сборке проекта, использующего эту библиотеку, maven поищет её в локальном хранилище, найдёт и подключит.


Итого


  • Maven ищет библиотеки в удалённом репозитории по умолчанию.
  • Чтобы подключить библиотеку, которой нет в репозитории по умолчанию, можно указать дополнительные удалённые репозитории, тогда maven будет искать библиотеки ещё и в них.
  • Если библиотеки нет ни в одном удалённом репозитории, то можно с помощью штатного механизма maven создать локальный репозиторий и добавить его в pom.xml.
  • При обновлении репозитория, который находится в исходниках проекта, нужно всегда менять версию библиотеки, иначе могут быть непонятные проблемы.
  • Если у вас есть maven проект, то из него можно сделать библиотеку командой mvn package.
  • Командой mvn install можно поместить библиотеку в локальный репозиторий по умолчанию.
  • Чтобы использовать библиотеку в другом проекте, достаточно указать её в качестве зависимости в pom.xml.

Комментарии (0)

© Habrahabr.ru