我们看一个最常见到的例子:
<project>
<modelVersion>4.0.0</modelVersion>
<groupId>com.mycompany.app</groupId>
<artifactId>my-app</artifactId>
<packaging>jar</packaging>
<version>1.0-SNAPSHOT</version>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>3.8.1</version>
<scope>test</scope>
</dependency>
</dependencies>
</project>
该例子表示你的project有一个junit dependency。你可能会问:这个dependency从哪里来?junit jar在哪里?
A dependency是对repository里的某个artifact的引用。POM定义了一个dependency,执行的时候就会根据dependency的groupId, artifactId and version,来search it from repository。你根本不需要在pom.xml里指明该dependancy来自哪个repository,maven会先查找local repository,如果local repository存在该dependancy引用的artifact,就使用它,如果不存在,则搜索所有你设置的remote repository,如果找到它,就把它download到local repository。缺省状态下,通常都是从central maven repository(http://www.ibiblio.org/maven2)来download artifact。如果你的pom.xml定义了多个remote repository,那么就按顺序依次试图从remote repository下载.
例如上面的例子,maven会先check local repository看是否有想要的junit artifact,如果没有,则从remote repository download到local repository。这时,local repository里artifact目录结构包含:
下图是在repository里所有artifact通用的目录结构:
groupId是fully qualified domain name,例如为x.y.z,则结构为:
maven是如何根据定义的dependancy来从repository里查找呢?例如上例,就会根据groupId “junit”, artifactId “junit”, and version “3.8.1”,在repository里查找~/.m2/repository/junit/junit/3.8.1/junit-3.8.1.jar。
dependancy功能是maven最强大的功能和最显著的优势。以前maven没出现之前,通常的project都会把要用到的jar files都放在project subdirectory下,或开发一个web app,你要把10多个jar添加到classpath,并把它们放到lib目录下。这样如果你开发100个类似的web app,你的每一个web app开发目录下面都会包含有这些jar files。这样如果某个jar的版本出现更新,就会要更新100个project里的jar。而使用maven,就会大大减轻你的工作量。
例如,你有100个web app都使用了spring 1.2.6 framework,如果你使用maven,你不需要存储所有的spring jars到各个project里,你只需要在POM.XML里定义一个spring dependancy,那么如果升级到spring 2.0,只需要把pom.xml里dependancy的<version>修改为2.0即可。
Dependency机制介绍
Dependency机制的三个知识点
- Transitive Dependencies
- Dependency Scope
- Dependency Management
Transitive Dependencies (可传递的依赖)
这是maven 2.0的新特征。它使你不需要指定dependency的位置而自动定位。而且可传递的依赖就是说依赖能够自动继承和传递,例如project A依赖project B的artifact,而project B则依赖project C的artifact,那么在build project A时,就会使用到所有project、子project的依赖。
一个project的依赖的总个数没有限制,但是如果出现死循环依赖则会出现问题。
由于依赖可以传递,因此有可能一个project要依赖的东东会很多,因此可以通过下列几种方式来限制要包括的dependency:
-
Dependency mediation – 意思是强烈建议显式设置你使用的dependency的版本号,因为dependency可能会有多种版本。目前Maven 2.0支持"nearest definition"(见下面的解释)。注意:如果在dependency tree的同一个depth里定义了同一个dependency的2个版本,那么使用先定义的那个版本。
-
"nearest definition" 表示在dependencies tree里最靠近你的project的版本。例如,如果project A的依赖性为:A -> B -> C -> D 2.0和A -> E -> D 1.0, 那么D的1.0版本将会被使用。因为从A通过E到达D的路径是最短的。如果本例你硬是想要使用D 2.0,那么你可以在A里定义一个D的dependency。
-
Dependency management – 表示maven允许你在你的pom.xml里设置你要使用的depedency的版本号,即使这个depedency你可能不知道是从哪里来的可传递依赖,也不知道该依赖定义的版本是什么,你都可以根据“nearest definition”法则来在你的pom.xml里设置版本号。例如上面的例子,你可以直接在A里设置对D的依赖(设置版本号),即使A并不直接使用D。
-
Dependency scope – 尽量为要包含的dependencies设置要用到它的scope。下面会详细解释
Dependency Scope
Dependency scope是设置什么stage要使用它,用来限制依赖的传递。
总共有5种Scopes:
-
compile – 这是缺省scope,表明是所有任务所需的资源。“Compile” dependencies are available in all classpaths.
-
provided – 表示该dependency是JDK部分或应用服务器的classpath里已经自带的资源,例如EJB的dependency jars,只需要在compile时使用,在例如打包时就不应该把它打包进jar, war or ear里,因为JDK or APP SERVER里本身就有。
-
runtime - this scope indicates that the dependency is not required for compilation, but is for execution. It is in the runtime and test classpaths, but not the compile classpath.
-
test – 表示该dependency只会在test compilation and execution phases使用。例如在使用junit依赖时,scope参数的值为test来告诉Maven这个依赖项只是在测试阶段所需的,而不是运行时所需的资源。
-
system - this scope is similar to provided except that you have to provide the JAR which contains it explicitly. The artifact is always available and is not looked up in a repository. 后面会详细讲解
不同的scope会影响“依赖的依赖”的scope。下表列出的就是当一个“依赖”的scope设置为最左一列的scope,那么设置成最上一行scope的“依赖的依赖”的scope将发生的变化列表。
|
Compile
|
provided
|
runtime
|
test
|
compile
|
compile(*)
|
-
|
runtime
|
-
|
provided
|
Provided
|
provided
|
provided
|
-
|
runtime
|
Runtime
|
-
|
runtime
|
_
|
Test
|
Test
|
-
|
test
|
-
|
Dependency Management
在parent pom里使用< dependencyManagement>来简化dependency设置。举个例子:
Project A:
<project>
...
<dependencies>
<dependency>
<groupId>group-a</groupId>
<artifactId>artifact-a</artifactId>
<version>1.0</version>
<exclusions>
<exclusion>
<groupId>group-c</groupId>
<artifactId>excluded-artifact</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>group-a</groupId>
<artifactId>artifact-b</artifactId>
<version>1.0</version>
<type>bar</type>
<scope>runtime</scope>
</dependency>
</dependencies>
</project>
Project B:
<project>
...
<dependencies>
<dependency>
<groupId>group-c</groupId>
<artifactId>artifact-b</artifactId>
<version>1.0</version>
<type>war</type>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>group-a</groupId>
<artifactId>artifact-b</artifactId>
<version>1.0</version>
<type>bar</type>
<scope>runtime</scope>
</dependency>
</dependencies>
</project>
下面通过在parent pom里使用< dependencyManagement>来管理child pom要使用的dependencies。
Parent Project:
<project>
...
<dependencyManagement>
<dependencies>
<dependency>
<groupId>group-a</groupId>
<artifactId>artifact-a</artifactId>
<version>1.0</version>
<exclusions>
<exclusion>
<groupId>group-c</groupId>
<artifactId>excluded-artifact</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>group-c</groupId>
<artifactId>artifact-b</artifactId>
<version>1.0</version>
<type>war</type>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>group-a</groupId>
<artifactId>artifact-b</artifactId>
<version>1.0</version>
<type>bar</type>
<scope>runtime</scope>
</dependency>
</dependencies>
</dependencyManagement>
</project>
使用上面parent pom就会简化child pom的dependency设置:
<project>
...
<dependencies>
<dependency>
<groupId>group-a</groupId>
<artifactId>artifact-a</artifactId>
</dependency>
<dependency>
<groupId>group-a</groupId>
<artifactId>artifact-b</artifactId>
<!-- This is not a jar dependency, so we must specify type. -->
<type>bar</type>
</dependency>
</dependencies>
</project>
注意:在上面的dependency引用中,非jar的必须使用<type> element。
Dependency management的另一个很有用的用处就是控制dependency的版本。还是举例:
Project A:
<project>
<modelVersion>4.0.0</modelVersion>
<groupId>maven</groupId>
<artifactId>A</artifactId>
<packaging>pom</packaging>
<name>A</name>
<version>1.0</version>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>test</groupId>
<artifactId>a</artifactId>
<version>1.2</version>
</dependency>
<dependency>
<groupId>test</groupId>
<artifactId>b</artifactId>
<version>1.0</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>test</groupId>
<artifactId>c</artifactId>
<version>1.2</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>test</groupId>
<artifactId>d</artifactId>
<version>1.2</version>
</dependency>
</dependencies>
</dependencyManagement>
</project>
Project B:
<project>
<parent>
<artifactId>A</artifactId>
<groupId>maven</groupId>
<version>1.0</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<groupId>maven</groupId>
<artifactId>B</artifactId>
<packaging>pom</packaging>
<name>B</name>
<version>1.0</version>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>test</groupId>
<artifactId>d</artifactId>
<version>1.0</version>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<dependency>
<groupId>maven-test</groupId>
<artifactId>a</artifactId>
<version>1.0</version>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>maven-test</groupId>
<artifactId>c</artifactId>
<scope>runtime</scope>
</dependency>
</dependencies>
</project>
上面可以看出project A是project B的parent,A和B都定义a, c, d dependencies,那么如果对project B执行maven命令,会采用哪个定义的呢?答案如下:
-
dependency a and c将会采用1.0版本。尽管在parent project A里定义的a and d的版本是1.2,但根据dependency mediation "nearest definition"特性,采用的是project B定义的版本。
-
dependency b只在parent project A里有定义,因此就采用project A的定义。即使Dependency c会使用不同版本的b, 如果执行project B还是会采用project A定义的版本(还是根据dependency mediation "nearest definition"特性)。
-
dependency d的情况和dependency b的差不多:由于它在A和B都用定义,因此是采用project B定义的版本1.0。假如Dependency c会使用不同版本的d, 如果执行project B还是会采用project B定义的版本(还是根据dependency mediation "nearest definition"特性)。
System scope Dependency
System scope的dependencies总是available的,而且不需要从repository里获取,因为定义成system scope的dependencies都是由JDK or VM提供的。典型的例子就是JDBC standard extensions和Java Authentication and Authorization Service (JAAS).
例子:
<project>
...
<dependencies>
<dependency>
<groupId>javax.sql</groupId>
<artifactId>jdbc-stdext</artifactId>
<version>2.0</version>
<scope>system</scope>
<systemPath>${java.home}/lib/rt.jar</systemPath>
</dependency>
</dependencies>
...
</project>
如果你的artifact来自JDK's tools.jar,那么system path应该定义为:
<project>
...
<dependencies>
<dependency>
<groupId>sun.jdk</groupId>
<artifactId>tools</artifactId>
<version>1.5.0</version>
<scope>system</scope>
<systemPath>${java.home}/../lib/tools.jar</systemPath>
</dependency>
</dependencies>
...
</project>
分享到:
相关推荐
Maven依赖的库都存储在Maven仓库中,包括本地仓库(默认在用户目录下)和远程仓库(如Central Repository)。当Maven找不到本地的依赖时,它会尝试从远程仓库下载。 8. **Maven的命令行选项**: Maven有许多...
例如,使用Maven或Gradle作为构建工具,它们可以从镜像站点或第三方库(如阿里云的Maven仓库)下载所需的Junit4.12及其依赖。在Maven的pom.xml文件中添加以下依赖: ```xml <dependency> <groupId>junit ...
It's based on a part of the Jawn Parser built on Arrow, a Functional companion to Kotlin's Standard Library. Adding the dependency Helios uses kotlin 1.3.10 version and Arrow 0.8.1 version. To import...
1. 添加依赖(如果是Maven项目): ```xml <dependency> <groupId>com.zaxxer</groupId> <artifactId>HikariCP 版本号 </dependency> ``` 2. 创建配置文件(如application.properties): ``` spring.datasource....
如果你使用的是Maven,可以在pom.xml文件中添加以下依赖: ```xml <dependency> <groupId>org.apache.poi <artifactId>poi <version>4.1.2 </dependency> <dependency> <groupId>org.apache.poi ...