目录
概述
Maven的一个重要的功能就是管理项目依赖。为了能够解析任何一个java构件,Maven就需要将它们唯一标识,这就是依赖管理的基础------坐标。
坐标详解
Maven坐标是通过一系列元素来定义的,比如:groupId, artifactId, version, packaging, classifier。
例如:
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>3.0.6.RELEASE</version>
</dependency>
groupId: 定义了当前Maven项目隶属的实际项目。通常一个项目被划分成多个模块。groupId表示方式:通常与域名一一反向对应。
artifactId: 定义了实际项目中的一个Maven项目(模块),推荐使用实际项目名作为前缀。可以参靠SpringFramework的模块命名。
version:该元素定义了当前Maven项目所处的版本。
packaging:该元素定义了Maven项目的打包方式。如果不定义packaging的时候,默认值为jar。还有别的方式,如war。
classifier:该元素用来帮助定义构建输出的一些附属构件。例如利用一些插件,可以生成附属构件,可以包括Java文档和源代码。注意,不能直接定义项目的classifier,因为附属构件不是项目直接默认生成的,而是由附加的插件帮助生成。
groupId,artifactId,version是必须定义的。packaging可选项。classifier 不可选的。
依赖的配置
根元素project下的dependencies可以包含一个或多个dependency元素,以声明一个或多个项目依赖。
在pom.xml中进行配置,
在project元素下进行配置依赖:
<dependencies>
<dependency>
<groupId>...</groupId>
<artifactId>...</artifactId>
<version>...</version>
<type>...</type>
<scope>...</scope>
<optional>...</optional>
<exclusions>
<exclusion>
...
</exclusion>
...
</exclusions>
</dependency>
...
</dependencies>
- type:依赖的类型,一般不用声明,默认为jar。
- scope:依赖的范围,下面有介绍
- optional:标记依赖是否可选。也可以理解为是否向下传递。在依赖中添加optional选项决定此依赖是否向下传递,如果是true则不传递,如果是false就传递,默认为false
- exclusions:用来排除传递性依赖
依赖范围
就是用来控制依赖与三种classpath的关系(编译classpath,测试classpath,运行classpath)
compile(编译)
编译依赖范围。如果没有指定,就会默认使用该依赖范围,该依赖范围对于编译,测试,运行都有效,同时它们也会被打包。
test(测试)
测试依赖范围。它们只有在测试编译和测试运行阶段可用,在编译主代码或运行项目时无效。
在Maven项目中,测试类一般是放在src/test/java,而不是放在src/main/java下。maven在编译的时候,src/main/java下是不引用test的jar;而编译src/test/java下的测试,就会引用test的jar。
runtime(运行时)
运行时依赖范围。对于测试和运行classpath有效,但在编译主代码时无效。比如,你可能在编译的时候只需要JDBC API JAR,而只有在运行的时候才需要JDBC驱动实现。
provided(已提供)
已提供依赖范围,只有在当JDK 或者一个容器已提供该依赖之后才使用。对于测试和编译classpath有效,但在运行时无效。例如servlet-api。
system(系统)
系统依赖范围。与三种classpath都有关系。system范围依赖与provided类似,但是你必须显式的提供一个对于本地系统中JAR文件的路径。这么做是为了允许基于本地对象编译,而这些对象是系统类库的一部分。这样的构建应该是一直可用的,Maven 也不会在仓库中去寻找它。如果你将一个依赖范围设置成系统范围,你必须同时提供一个systemPath元素。注意该范围是不推荐使用的(建议尽量去从公共或定制的 Maven 仓库中引用依赖
传递性依赖
举例来说,我们在项目中使用Spring Framework时,需要在POM文件中写对Spring的依赖(例如:spring-core),在本地仓库中,它也是有自己的pom文件,这里面就定义了该子项目或者jar包的依赖。Maven会解析各个直接依赖的pom,将那些必要的间接依赖,以传递性依赖的方式引入到当前项目。
传递性依赖和依赖范围
依赖范围,需要着重理解。
例如:A依赖于B,B依赖于C,那么A对于B来说是第一直接依赖
,B对于C来说是第二直接依赖
,A对于C来说就是传递性依赖
。
第一直接依赖的范围和第二直接依赖的范围决定了传递性依赖的范围;
当第二依赖的范围是compile的时候,依赖可以传递
当第二直接依赖的范围是test的时候,依赖不会得以传递
依赖调节
一共有两个原则:
第一原则:路径最近者优先
第二原则:从2.0.9版本开始,第一声明者优先
最佳实践
- 排除依赖
使用exclusions元素声明排除依赖 - 归类依赖
使用美元符号和大括号环绕的方式引用Maven属性 - 优化依赖
查看当前项目的已解析依赖,用下面的命令:
查看当前项目的依赖树,用下面的命令:mvn dependency:list
帮助分析当前项目的依赖,命令如下:mvn dependency:tree
mvn dependency:analyze
maven继承
继承
继承是为了消除重复,可以把很多相同的配置提取出来。例如:grouptId,version等
假设目前有四个maven项目,分别是project.parent、project.test1、project.test2、project.test3
要求test1、test2、test3整合到一个项目,并且从project.parent继承依赖
parent聚合test1、test2、test3三个项目
<packaging>pom</packaging>
<modules>
<module>../project.test1</module>
<module>../project.test2</module>
<module>../project.test3</module>
</modules>
执行clean compile 进行验证,会同时编译test1、test2、test3三个项目
test1、test2、test3分别关联parent项目
<parent>
<groupId>com.project</groupId>
<artifactId>project.parent</artifactId>
<version>0.0.1-SNAPSHOT</version>
</parent>
会自动继承父类的依赖jar
父工程统一管理依赖
在父工程中通过配置dependencies依赖,子工程可以直接继承使用。
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.10</version>
<scope>test</scope>
</dependency>
</dependencies>
如果把父类依赖放在<dependencyManagement>
中管理,则子类不会自动成父类的依赖