Как с помощью maven работать с библиотеками, которых в maven нет
В статье я расскажу, как подключить библиотеку, которой в maven по умолчанию нет, и как подключить другую библиотеку, исходники которой давным-давно потеряны.
Также я опишу, как сделать maven проект, который генерирует артефакт, по совместительству являющийся библиотекой, и как подключить эту библиотеку к другому своему же maven проекту.
Эта статья для тех, кто только начинает осваивать java.
В моей предыдущей статье было сказано, что 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 появится файл с названием \
Как подключить свежесозданную библиотеку к своему 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.