Maven 一个核心的特性就是依赖管理。当我们处理多模块的项目(包含成百上千个模块或者子项目),模块间的依赖关系就变得非常复杂,管理也变得很困难。针对此种情形,Maven 提供了一种高度控制的方法。
假如我们有两个项目helloMaven和hiMaven,hiMaven需要引用helloMaven中的getName()方法,这时在hiMaven的pom中直接引用肯定是不行的,会报“无法找到依赖的错误”
Failed to execute goal on project test: Could not resolve dependencies for project com.companyname.project-group:test:jar:1.0: Could not find artifact com.companyname.project-group:hello:jar:1.0 in central (https://repo.maven.apache.org/maven2) -> [Help 1]
所以我们需要将helloMaven添加到maven仓库中,以便其他项目引用
1.如何将自己创建的项目添加至maven仓库
执行install命令
执行完成后会将我们的项目打成jar包添加至本地的maven仓库中
2.如何在maven项目中引用外部依赖
我们只需要在hiMaven的pom中添加以下代码即可,maven就会根据groupid、artifactId、version区定位到仓库中的依赖文件
<dependencies>
<dependency>
<groupId>com.companyname.project-group</groupId>
<artifactId>hello</artifactId>
<version>1.0</version>
</dependency>
</dependencies>
pom.xml 文件完整代码如下:
<project xmlns = "http://maven.apache.org/POM/4.0.0"
xmlns:xsi = "http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation = "http://maven.apache.org/POM/4.0.0
http://maven.apache.org/xsd/maven-4.0.0.xsd">
<!-- 模型版本 -->
<modelVersion>4.0.0</modelVersion>
<!-- 公司或者组织的唯一标志,并且配置时生成的路径也是由此生成, 如com.companyname.project-group,maven会将该项目打成的jar包放本地路径:/com/companyname/project-group -->
<groupId>com.companyname.project-group</groupId>
<!-- 项目的唯一ID,一个groupId下面可能多个项目,就是靠artifactId来区分的 -->
<artifactId>test</artifactId>
<!-- 版本号 -->
<version>1.0</version>
<name>test</name>
<dependencies>
<dependency>
<groupId>com.companyname.project-group</groupId>
<artifactId>hello</artifactId>
<version>1.0</version>
</dependency>
</dependencies>
</project>
然后在hiMaven下执行mvn compile就可以成功编译了
3.maven依赖的作用范围
传递依赖发现可以通过使用如下的依赖范围来得到限制:
范围 | 描述 |
---|---|
编译阶段 | 该范围表明相关依赖是只在项目的类路径下有效。默认取值。 |
供应阶段 | 该范围表明相关依赖是由运行时的 JDK 或者 网络服务器提供的。 |
运行阶段 | 该范围表明相关依赖在编译阶段不是必须的,但是在执行阶段是必须的。 |
测试阶段 | 该范围表明相关依赖只在测试编译阶段和执行阶段。 |
系统阶段 | 该范围表明你需要提供一个系统路径。 |
导入阶段 | 该范围只在依赖是一个 pom 里定义的依赖时使用。同时,当前项目的POM 文件的 部分定义的依赖关系可以取代某特定的 POM。 |
maven依赖的作用范围是用scope标签进行声明的,主要常用的三个值是:compile、test、provided,如果没有配置scope则默认为compile
声明方式:
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>3.8.1</version>
<scope>compile/test/provided</scope>
</dependency>
下表简单说明了三种依赖声明方式的作用范围
compile | test | provided | |
---|---|---|---|
对主程序是否有效 | 有效 | 无效 | 有效 |
对测试程序是否有效 | 有效 | 有效 | 有效 |
是否参与打包 | 参与 | 不参与 | 不参与 |
- 我们可以根据主程序和测试程序的区别理解compile和test的依赖作用范围
当我们想要在main下的项目中引用test的方法时,编译就会报错;典型的例子就是“junit”。 - 我们可以根据web项目的开发流程,来理解compile和provided依赖的作用范围
provided的依赖在开发过程中对mian和test都是可见的,但是它不会参与打包;典型例子就是“servlet-api.jar”
tip: 我们在声明依赖范围时需要注意依赖的冲突的问题
4.maven依赖的主要特性
1.依赖的传递性
maven的依赖有一个非常重要的特性——依赖的可传递性,例如:A 依赖于其他库 B。如果,另外一个项目 C 想要使用 A ,那么 C 项目也需要使用库 B。
tip: 非compile的依赖是不能进行传递的,所以其他模块在引用的时候,非compile的依赖必须重复进行声明
依赖的传递主要遵循两个原则:
短路原则:当引用传递的依赖在不同深度的依赖中都有声明时,当前maven项目会选择更接近直接引用的版本;
短路原则其实就是当你在当前maven项目的pom.xml中显示声明了一个依赖时,本应从下层依赖中传递给你的相同依赖,就不会再进行传递了
优先原则:当引用的层级相同时,会选择在当前maven项目的pom.xml中先声明的依赖,这里的先后指的是在标签中声明的顺序;
2.依赖的排除性
因为依赖的传递性,所以我们在引用依赖时有可能将不想引用依赖通过我们想要引用的依赖传递过来,比如我们的A项目需要依赖 B, 但是B又依赖了C,而我们的A并不想引用C,这时我们就可以在“dependency”下使用"exclusion"元素将C排除在引用范围之外
<dependency>
<groupId>ytangtech</groupId>
<artifactId>hhisp-docinf</artifactId>
<version>0.0.1-SNAPSHOT</version>
<scope>compile</scope>
<exclusions>
<exclusion>
<groupId>C 的groupId</groupId>
<artifactId>C 的artifactId</artifactId>
</exclusion>
</exclusions>
</dependency>
1.声明exclusion时不需要指定版本,这时会将C引用的任意版本都排除在外
2.需要使用这个属性的场景一般就是C为不稳定的版本所以我们需要将它排除,但是一般我们都不会使用这个属性,因为谁知道会出什么幺蛾子