Apache Maven — отличная штука, для управления сторонними зависимостями в вашем проекте. Достаточно сказать ему, какой артефакт вам нужен и всё остальное Maven сделает сам.
Добавление зависимостей
Все зависимости перечисляются в секции <dependencies/>, одна за одной, в любом порядке.
1
2
3
4
5
6
7
8
|
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>3.8.2</version>
<scope>test</scope>
</dependency>
</dependencies>
|
Например, в архетипе quickstart автоматически добавляется библиотека JUnit3. Если мы хотим перейти с JUnit3 на JUnit4, то достаточно изменить версию в зависимости:
1
2
3
4
5
6
7
8
|
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
</dependencies>
|
Чтобы добавить какую-нибудь другую зависимость, например TestNG, надо знать её maven координаты, то есть группу, артефакт и версию:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
<code>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
<b>
<dependency>
<groupId>org.testng</groupId>
<artifactId>testng</artifactId>
<version>6.11</version>
<scope>test</scope>
</dependency>
</b>
</dependencies>
</code>
|
Переменные в maven
Перед тем как продолжить добавлять зависимости, нужно сделать шаг к переменным в maven. Maven позволяет задавать переменные (а сам задаёт ещё больше), значения которых впоследствии можно использовать где угодно:
1
2
3
4
5
6
|
<properties>
<myvar>1.2.3</myvar>
</properties>
<!-- далее в коде -->
<version>${myvar}</version>
|
И в тег <version/> будет подставлено значение «1.2.3».
Те же самые переменные можно и нужно использоват, чтобы задавать версию зависимости отдельно от самой зависимости:
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
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
|
<properties>
<junit.version>4.10</junit.version>
<testng.version>6.1.1</testng.version>
<spring.version>3.1.3.RELEASE</spring.version>
</properties>
<dependencies>
<!-- Unit testing utitilies -->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>${junit.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.testng</groupId>
<artifactId>testng</artifactId>
<version>${testng.version}</version>
<scope>test</scope>
</dependency>
<!-- Spring -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>${org.springframework.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-tx</artifactId>
<version>${org.springframework.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-orm</artifactId>
<version>${org.springframework.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>${org.springframework.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-expression</artifactId>
<version>${org.springframework.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
<version>${org.springframework.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>${org.springframework.version}</version>
</dependency>
</dependencies>
|
Такое раздельное описание зависимостей имеет два преимущества:
- В одном списке, который можно окинуть одним взглядом, перечислены зависимости и их версии.
- Некоторые библиотеки (скажем Spring) состоят из нескольких артефактов с одной и той же версией и, таким образом, проще изменить версию только в одном месте, чем в нескольких
Кстати, подписывать какие зависимости для чего нужны, тоже не лишне.
Области видимости
Вы могли заметить, что описания зависимостей для JUnit и Spring framework отличаются параметром scope, он же — область видимости. Scope позволяет указать maven’у когда и для чего вам нужна эта зависимость. Всего существует шесть областей видимости:
- compile — область видимости по умолчанию. Зависимости с этим scope будут доступны и во время сборки и во время тестирования и их даже добавят в конечный пакет, чтобы они были доступны и во время исполнения. Более того, maven распространит их дальше и сделает доступными в зависимых пакетах.
- provided — Почти как compile, но в пакет зависимость добавлена не будет. Предполагается что данные библиотеки будут предоставлены средой выполнения, например J2EE контейнером. Каноничный пример такой зависимости — J2EE API, конкретная реализация которых предоставляется контейнером J2EE.
- runtime — антипод provided. Означает зависимость, которая требуется для исполнения/тестирования кода, но не для его сборки. Зависимости из этого
scope так же будут добавлены в пакет. - test — зависимости, которые нужны только и исключительно для тестов. Как JUnit из примера выше.
- system — зависимость которая присутствует в среде Java всегда, тем или иным путём. Maven не будет пытаться предоставить этот артефакт или класть
его в пакет итд. - import — использутся для импорта зависимостей из других артефактов и управлением зависимостями в сложных пакетах, состоящих из нескольких артефактов.
Например, в одном из моих проектов есть такие зависимости:
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
|
<!-- Lombok code generator -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>${lombok.annotations}</version>
<scope>provided</scope>
</dependency>
<!-- Logging -->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>${slf4j.version}</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<version>${slf4j.version}</version>
<scope>runtime</scope>
</dependency>
<!-- Unit testing -->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>${junit.version}</version>
<scope>test</scope>
</dependency>
|
- org.projectlombok:lombok — утилита для генерации кода, работающая только во время компиляции. Поэтому у неё scope — provided
- org.slf4j:slf4j-api — Фронтенд для ведения логов. Мой проект с ним собирается, тестируется и работает. Scope Slf4j — compile.
- org.slf4j:slf4j-log4j12 — Реализация Slf4j поверх log4j. Мой проект не ссылается напрямую на эту библиотеку и использует её только посредством Slf4j, поэтому её Scope — runtime.
- junit:junit — Фреймворк юнит-тестирования. Очевидно что он нужен только во время исполнения тестов и из-за этого его scope — test.
Области видимости system и import используются крайне редко.
Исключение зависимостей
Как я уже писал выше, maven весьма удобная штука для управления зависимостями. И достаточно умная, чтобы понять, что у зависимостей бывают зависимости, а у них свои зависимости и т. д. И если вы добавите в pom.xml скажем, hibernate, то maven самостоятельно добавит ещё antlr, commons-collections, dom4j и так далее.
1
2
3
4
5
6
7
8
9
10
|
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-core</artifactId>
<version>${hibernate.version}</version>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-entitymanager</artifactId>
<version>${hibernate.version}</version>
</dependency>
|
Но иногда хочется сказать maven, чтобы он так не делал. Положим у вас есть две библиотеки X и Y, причём Y явно зависит от библиотеки X другой версии. Maven предоставит вам и то и другое и у вас случится конфликт. Для этого стоит научится исключать зависимости из зависимостей:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
<dependency>
<groupId>org.dbunit</groupId>
<artifactId>dbunit</artifactId>
<version>${dbunit.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.unitils</groupId>
<artifactId>unitils-dbmaintainer</artifactId>
<version>${unitils.version}</version>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>org.dbunit</groupId>
<artifactId>dbunit</artifactId>
</exclusion>
</exclusions>
</dependency>
|
Я знаю, что unitils-dbmaintainer зависит от dbunit предыдущей версии, но тесты моего приложения зависят от более новой версии. Поэтому я явно добавляю зависимость от dbunit нужной мне версии и исключаю старый dbunit из зависимостей unitils-dbmaintainer.
Чтобы просмотреть, какие именно зависимости (с учётом их зависимостей) имеет ваш артефакт, можно попросить maven нарисовать дерево зависимостей:
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
42
43
44
45
46
47
48
49
|
$ mvn dependency:tree
[INFO] Scanning for projects...
[INFO] Searching repository for plugin with prefix: 'dependency'.
[INFO] ------------------------------------------------------------------------
[INFO] Building exclude
[INFO] task-segment: [dependency:tree]
[INFO] ------------------------------------------------------------------------
[INFO] [dependency:tree {execution: default-cli}]
[INFO] ru.morningjava.maven:exclude:jar:1.0
[INFO] +- junit:junit:jar:4.10:test
[INFO] | \- org.hamcrest:hamcrest-core:jar:1.1:test
[INFO] +- org.testng:testng:jar:6.1.1:test
[INFO] | +- org.beanshell:bsh:jar:2.0b4:test
[INFO] | +- com.beust:jcommander:jar:1.12:test
[INFO] | \- org.yaml:snakeyaml:jar:1.6:test
[INFO] +- org.dbunit:dbunit:jar:2.4.9:test
[INFO] | +- org.slf4j:slf4j-api:jar:1.5.6:test
[INFO] | \- commons-collections:commons-collections:jar:3.2.1:test
[INFO] +- org.unitils:unitils-dbmaintainer:jar:3.3:test
[INFO] | +- org.unitils:unitils-core:jar:3.3:test
[INFO] | | +- commons-lang:commons-lang:jar:2.3:test
[INFO] | | \- ognl:ognl:jar:2.6.9:test
[INFO] | \- org.hibernate:hibernate:jar:3.2.5.ga:test
[INFO] | +- net.sf.ehcache:ehcache:jar:1.2.3:test
[INFO] | +- asm:asm-attrs:jar:1.5.3:test
[INFO] | +- dom4j:dom4j:jar:1.6.1:test
[INFO] | +- antlr:antlr:jar:2.7.6:test
[INFO] | +- cglib:cglib:jar:2.1_3:test
[INFO] | \- asm:asm:jar:1.5.3:test
[INFO] +- org.springframework:spring-context:jar:3.1.3.RELEASE:compile
[INFO] | +- org.springframework:spring-aop:jar:3.1.3.RELEASE:compile
[INFO] | +- org.springframework:spring-beans:jar:3.1.3.RELEASE:compile
[INFO] | +- org.springframework:spring-core:jar:3.1.3.RELEASE:compile
[INFO] | | \- commons-logging:commons-logging:jar:1.1.1:compile
[INFO] | \- org.springframework:spring-asm:jar:3.1.3.RELEASE:compile
[INFO] +- org.springframework:spring-tx:jar:3.1.3.RELEASE:compile
[INFO] | \- aopalliance:aopalliance:jar:1.0:compile
[INFO] +- org.springframework:spring-test:jar:3.1.3.RELEASE:compile
[INFO] +- org.springframework:spring-expression:jar:3.1.3.RELEASE:compile
[INFO] \- org.springframework:spring-webmvc:jar:3.1.3.RELEASE:compile
[INFO] +- org.springframework:spring-context-support:jar:3.1.3.RELEASE:compile
[INFO] \- org.springframework:spring-web:jar:3.1.3.RELEASE:compile
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESSFUL
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 2 seconds
[INFO] Finished at: Thu Nov 15 14:05:31 EET 2012
[INFO] Final Memory: 18M/307M
[INFO] ------------------------------------------------------------------------
|
Или тоже самое, но с подробностями:
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
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
|
$ mvn dependency:tree -Dverbose=true
[INFO] Scanning for projects...
[INFO] Searching repository for plugin with prefix: 'dependency'.
[INFO] ------------------------------------------------------------------------
[INFO] Building exclude
[INFO] task-segment: [dependency:tree]
[INFO] ------------------------------------------------------------------------
[INFO] [dependency:tree {execution: default-cli}]
[INFO] ru.morningjava.maven:exclude:jar:1.0
[INFO] +- junit:junit:jar:4.10:test
[INFO] | \- org.hamcrest:hamcrest-core:jar:1.1:test
[INFO] +- org.testng:testng:jar:6.1.1:test
[INFO] | +- (junit:junit:jar:3.8.1:test - omitted for conflict with 4.10)
[INFO] | +- org.beanshell:bsh:jar:2.0b4:test
[INFO] | +- com.beust:jcommander:jar:1.12:test
[INFO] | \- org.yaml:snakeyaml:jar:1.6:test
[INFO] +- org.dbunit:dbunit:jar:2.4.9:test
[INFO] | +- org.slf4j:slf4j-api:jar:1.5.6:test
[INFO] | +- (junit:junit:jar:3.8.2:test - omitted for conflict with 4.10)
[INFO] | \- commons-collections:commons-collections:jar:3.2.1:test
[INFO] +- org.unitils:unitils-dbmaintainer:jar:3.3:test
[INFO] | +- org.unitils:unitils-core:jar:3.3:test
[INFO] | | +- (junit:junit:jar:4.4:test - omitted for conflict with 4.10)
[INFO] | | +- (commons-logging:commons-logging:jar:1.1:compile - scope updated from test; omitted for duplicate)
[INFO] | | +- commons-lang:commons-lang:jar:2.3:test
[INFO] | | +- (commons-collections:commons-collections:jar:3.2:test - omitted for conflict with 3.2.1)
[INFO] | | \- ognl:ognl:jar:2.6.9:test
[INFO] | \- org.hibernate:hibernate:jar:3.2.5.ga:test
[INFO] | +- net.sf.ehcache:ehcache:jar:1.2.3:test
[INFO] | | +- (commons-logging:commons-logging:jar:1.0.4:test - omitted for conflict with 1.1)
[INFO] | | \- (commons-collections:commons-collections:jar:2.1:test - omitted for conflict with 3.2.1)
[INFO] | +- (commons-logging:commons-logging:jar:1.0.4:test - omitted for conflict with 1.1)
[INFO] | +- asm:asm-attrs:jar:1.5.3:test
[INFO] | +- dom4j:dom4j:jar:1.6.1:test
[INFO] | +- antlr:antlr:jar:2.7.6:test
[INFO] | +- cglib:cglib:jar:2.1_3:test
[INFO] | | \- (asm:asm:jar:1.5.3:test - omitted for duplicate)
[INFO] | +- asm:asm:jar:1.5.3:test
[INFO] | \- (commons-collections:commons-collections:jar:2.1.1:test - omitted for conflict with 3.2.1)
[INFO] +- org.springframework:spring-context:jar:3.1.3.RELEASE:compile
[INFO] | +- org.springframework:spring-aop:jar:3.1.3.RELEASE:compile
[INFO] | | +- (aopalliance:aopalliance:jar:1.0:compile - omitted for duplicate)
[INFO] | | +- (org.springframework:spring-asm:jar:3.1.3.RELEASE:compile - omitted for duplicate)
[INFO] | | +- (org.springframework:spring-beans:jar:3.1.3.RELEASE:compile - omitted for duplicate)
[INFO] | | \- (org.springframework:spring-core:jar:3.1.3.RELEASE:compile - omitted for duplicate)
[INFO] | +- org.springframework:spring-beans:jar:3.1.3.RELEASE:compile
[INFO] | | \- (org.springframework:spring-core:jar:3.1.3.RELEASE:compile - omitted for duplicate)
[INFO] | +- org.springframework:spring-core:jar:3.1.3.RELEASE:compile
[INFO] | | +- (org.springframework:spring-asm:jar:3.1.3.RELEASE:compile - omitted for duplicate)
[INFO] | | \- commons-logging:commons-logging:jar:1.1.1:compile
[INFO] | +- (org.springframework:spring-expression:jar:3.1.3.RELEASE:compile - omitted for duplicate)
[INFO] | \- org.springframework:spring-asm:jar:3.1.3.RELEASE:compile
[INFO] +- org.springframework:spring-tx:jar:3.1.3.RELEASE:compile
[INFO] | +- aopalliance:aopalliance:jar:1.0:compile
[INFO] | +- (org.springframework:spring-aop:jar:3.1.3.RELEASE:compile - omitted for duplicate)
[INFO] | +- (org.springframework:spring-beans:jar:3.1.3.RELEASE:compile - omitted for duplicate)
[INFO] | +- (org.springframework:spring-context:jar:3.1.3.RELEASE:compile - omitted for duplicate)
[INFO] | \- (org.springframework:spring-core:jar:3.1.3.RELEASE:compile - omitted for duplicate)
[INFO] +- org.springframework:spring-test:jar:3.1.3.RELEASE:compile
[INFO] +- org.springframework:spring-expression:jar:3.1.3.RELEASE:compile
[INFO] | \- (org.springframework:spring-core:jar:3.1.3.RELEASE:compile - omitted for duplicate)
[INFO] \- org.springframework:spring-webmvc:jar:3.1.3.RELEASE:compile
[INFO] +- (org.springframework:spring-asm:jar:3.1.3.RELEASE:compile - omitted for duplicate)
[INFO] +- (org.springframework:spring-beans:jar:3.1.3.RELEASE:compile - omitted for duplicate)
[INFO] +- (org.springframework:spring-context:jar:3.1.3.RELEASE:compile - omitted for duplicate)
[INFO] +- org.springframework:spring-context-support:jar:3.1.3.RELEASE:compile
[INFO] | +- (org.springframework:spring-beans:jar:3.1.3.RELEASE:compile - omitted for duplicate)
[INFO] | +- (org.springframework:spring-context:jar:3.1.3.RELEASE:compile - omitted for duplicate)
[INFO] | \- (org.springframework:spring-core:jar:3.1.3.RELEASE:compile - omitted for duplicate)
[INFO] +- (org.springframework:spring-core:jar:3.1.3.RELEASE:compile - omitted for duplicate)
[INFO] +- (org.springframework:spring-expression:jar:3.1.3.RELEASE:compile - omitted for duplicate)
[INFO] \- org.springframework:spring-web:jar:3.1.3.RELEASE:compile
[INFO] +- (aopalliance:aopalliance:jar:1.0:compile - omitted for duplicate)
[INFO] +- (org.springframework:spring-aop:jar:3.1.3.RELEASE:compile - omitted for duplicate)
[INFO] +- (org.springframework:spring-beans:jar:3.1.3.RELEASE:compile - omitted for duplicate)
[INFO] +- (org.springframework:spring-context:jar:3.1.3.RELEASE:compile - omitted for duplicate)
[INFO] \- (org.springframework:spring-core:jar:3.1.3.RELEASE:compile - omitted for duplicate)
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESSFUL
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 2 seconds
[INFO] Finished at: Thu Nov 15 14:06:14 EET 2012
[INFO] Final Memory: 17M/253M
[INFO] ------------------------------------------------------------------------
|