在por.xml配置中会添加所需要引入的jar包,前面已经知道,jar包有三要素:必须写
groupId:公司或组织的id
artifactId:一个项目或者是项目中的一个模块的id
version:版本号
但其实还有scope属性,这个代表依赖程度,比如有些jar包只需要在测试时使用,打包成项目时不需要这个jar包,就可以设置为test等级,这样可以减少今后打包部署项目时的所占容量
标签的位置:dependencies/dependency/scope
标签的可选值:compile/test/provided
main目录(空间) | test目录(空间) | 开发过程(时间) | 部署到服务器(时间) | |
---|---|---|---|---|
compile | 有效 | 有效 | 有效 | 有效 |
test | 无效 | 有效 | 有效 | 无效 |
main目录(空间) | test目录(空间) | 开发过程(时间) | 部署到服务器(时间) | |
---|---|---|---|---|
compile | 有效 | 有效 | 有效 | 有效 |
provided | 有效 | 有效 | 有效 | 无效 |
compile:通常使用的第三方框架的jar包这样在项目实际运行时真正要用到的jar包都是以compile范围进行依赖的。比如SSM框架所需jar包。
test:测试过程中使用的jar包,以test范围依赖进来。比如junit。
provided:在开发过程中需要用到的“服务器上的jar包”通常以provided范围依赖进来。比如servlet-api、jsp-api。而这个范围的jar包之所以不参与部署、不放进war包,就是避免和服务器上已有的同类jar包产生冲突,同时减轻服务器的负担。说白了就是:“服务器上已经有了,你就别带啦!”
测试方式:在主体程序中导入org.junit.Test这个注解,然后执行编译。
具体操作:在pro01-maven-java\src\main\java\com\kevin\maven目录下修改Calculator.java
package com.kevin.maven;
import org.junit.Test;
public class Calculator {
public int sum(int i, int j){
return i + j;
}
}
执行Maven编译命令:
[ERROR] /D:/maven-workspace/space201026/pro01-maven-java/src/main/java/com/kevin/maven/Calculator.java:[3,17] 程序包org.junit不存在
其实就是验证:通过compile范围依赖的jar包会放入war包,通过test范围依赖的jar包不会放入war包。
junit
junit
4.11
test
javax.servlet
javax.servlet-api
4.0.1
provided
com.atguigu
pro01-maven-java
1.0-SNAPSHOT
provided
执行compile packge,找到打包的项目并解压,进入webapp->WEBINF->lib->看看有没有上面三个包,可以发现在打包时,test和provided属性的都是不打进包的
测试方式是在pro02-maven-web的测试程序中加入servlet-api.jar包中的类。
修改:pro02-maven-web\src\test\java\com\kevin\maven\CalculatorTest.java
package com.kevin.maven;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.ServletException;
import org.junit.Test;
import com.kevin.maven.Calculator;
// 静态导入的效果是将Assert类中的静态资源导入当前类
// 这样一来,在当前类中就可以直接使用Assert类中的静态资源,不需要写类名
import static org.junit.Assert.*;
public class CalculatorTest{
@Test
public void testSum(){
// 1.创建Calculator对象
Calculator calculator = new Calculator();
// 2.调用Calculator对象的方法,获取到程序运行实际的结果
int actualResult = calculator.sum(5, 3);
// 3.声明一个变量,表示程序运行期待的结果
int expectedResult = 8;
// 4.使用断言来判断实际结果和期待结果是否一致
// 如果一致:测试通过,不会抛出异常
// 如果不一致:抛出异常,测试失败
assertEquals(expectedResult, actualResult);
}
}
然后运行Maven的编译命令:mvn compile
然后看到编译成功。
mvn dependency:list
[INFO] The following files have been resolved:
[INFO] org.hamcrest:hamcrest-core:jar:1.3:test
[INFO] javax.servlet:javax.servlet-api:jar:3.1.0:provided
[INFO] com.kevin.maven:pro01-maven-java:jar:1.0-SNAPSHOT:compile
[INFO] junit:junit:jar:4.12:test
说明:javax.servlet:javax.servlet-api:jar:3.1.0:provided格式显示的是一个jar包的坐标信息。格式是:
groupId:artifactId:打包方式:version:依赖的范围
这样的格式虽然和我们XML配置文件中坐标的格式不同,但是本质上还是坐标信息,大家需要能够认识这样的格式,将来从Maven命令的日志或错误信息中看到这样格式的信息,就能够识别出来这是坐标。进而根据坐标到Maven仓库找到对应的jar包,用这样的方式解决我们遇到的报错的情况。
mvn dependency:tree
[INFO] com.atguigu.maven:pro02-maven-web:war:1.0-SNAPSHOT
[INFO] +- junit:junit:jar:4.12:test
[INFO] | - org.hamcrest:hamcrest-core:jar:1.3:test
[INFO] +- javax.servlet:javax.servlet-api:jar:3.1.0:provided
[INFO] - com.kevin.maven:pro01-maven-java:jar:1.0-SNAPSHOT:compile
我们在pom.xml中并没有依赖hamcrest-core,但是它却被加入了我们依赖的列表。原因是:junit依赖了hamcrest-core,然后基于依赖的传递性,hamcrest-core被传递到我们的工程了。
A依赖B,B依赖C,那么在A没有配置对C的依赖的情况下,A里面能不能直接使用C?
在A依赖B,B依赖C的前提下,C是否能够传递到A,取决于B依赖C时使用的依赖范围。
当A依赖B,B依赖C而且C可以传递到A的时候,但是A不想要C,需要在A里面把C排除掉。而往往这种情况都是为了避免jar包之间的冲突。
所以配置依赖的排除其实就是阻止某些jar包的传递。因为这样的jar包传递过来会和其他jar包冲突。
com.atguigu.maven
pro01-maven-java
1.0-SNAPSHOT
compile
commons-logging
commons-logging
Maven工程之间,A工程继承B工程
本质上是A工程的pom.xml中的配置继承了B工程中pom.xml的配置。
在父工程中统一管理项目中的依赖信息,具体来说是管理依赖信息的版本。
在一个工程中依赖多个Spring的jar包
[INFO] +- org.springframework:spring-core:jar:4.0.0.RELEASE:compile [INFO] | - commons-logging:commons-logging:jar:1.1.1:compile [INFO] +- org.springframework:spring-beans:jar:4.0.0.RELEASE:compile [INFO] +- org.springframework:spring-context:jar:4.0.0.RELEASE:compile [INFO] +- org.springframework:spring-expression:jar:4.0.0.RELEASE:compile [INFO] +- org.springframework:spring-aop:jar:4.0.0.RELEASE:compile [INFO] | - aopalliance:aopalliance:jar:1.0:compile
使用Spring时要求所有Spring自己的jar包版本必须一致。为了能够对这些jar包的版本进行统一管理,我们使用继承这个机制,将所有版本信息统一在父工程中进行管理。
①创建父工程
创建的过程和前面创建pro01-maven-java一样。
工程名称:pro03-maven-parent
工程创建好之后,要修改它的打包方式:
com.atguigu.maven
pro03-maven-parent
1.0-SNAPSHOT
pom
只有打包方式为pom的Maven工程能够管理其他Maven工程。
②创建模块工程
模块工程类似于IDEA中的module,所以需要进入pro03-maven-parent工程的根目录,然后运行mvn archetype:generate命令来创建模块工程。
假设,我们创建三个模块工程:
③查看被添加新内容的父工程pom.xml
下面modules和module标签是聚合功能的配置
pro04-maven-module
pro05-maven-module
pro06-maven-module
④解读子工程的pom.xml
com.atguigu.maven
pro03-maven-parent
1.0-SNAPSHOT
pro04-maven-module
⑤在父工程中配置依赖的统一管理(必须在dependency Management标签下)
org.springframework
spring-core
4.0.0.RELEASE
org.springframework
spring-beans
4.0.0.RELEASE
org.springframework
spring-context
4.0.0.RELEASE
org.springframework
spring-expression
4.0.0.RELEASE
org.springframework
spring-aop
4.0.0.RELEASE
⑥子工程中引用那些被父工程管理的依赖
关键点:省略版本号
org.springframework
spring-core
org.springframework
spring-beans
org.springframework
spring-context
org.springframework
spring-expression
org.springframework
spring-aop
⑦在父工程中升级依赖信息的版本
……
org.springframework
spring-beans
4.1.4.RELEASE
……
然后在子工程中运行mvn dependency:list,效果如下:
[INFO] org.springframework:spring-aop:jar:4.1.4.RELEASE:compile [INFO] org.springframework:spring-core:jar:4.1.4.RELEASE:compile [INFO] org.springframework:spring-context:jar:4.1.4.RELEASE:compile [INFO] org.springframework:spring-beans:jar:4.1.4.RELEASE:compile [INFO] org.springframework:spring-expression:jar:4.1.4.RELEASE:compile
⑧在父工程中声明自定义属性
UTF-8
4.3.6.RELEASE
在需要的地方使用${}的形式来引用自定义的属性名:
org.springframework
spring-core
${atguigu.spring.version}
真正实现“一处修改,处处生效”。
编写一套符合要求、开发各种功能都能正常工作的依赖组合并不容易。如果公司里已经有人总结了成熟的组合方案,那么再开发新项目时,如果不使用原有的积累,而是重新摸索,会浪费大量的时间。为了提高效率,我们可以使用工程继承的机制,让成熟的依赖组合方案能够保留下来。
如上图所示,公司级的父工程中管理的就是成熟的依赖组合方案,各个新项目、子系统各取所需即可。
部分组成整体
使用一个“总工程”将各个“模块工程”汇集起来,作为一个整体对应完整的项目。
概念的对应关系:
从继承关系角度来看:
- 父工程
- 子工程
从聚合关系角度来看:
- 总工程
- 模块工程
一键执行Maven命令:很多构建命令都可以在“总工程”中一键执行。
以mvn install命令为例:Maven要求有父工程时先安装父工程;有依赖的工程时,先安装依赖的工程。我们自己考虑这些规则会很麻烦。但是工程聚合之后,在总工程执行mvn install可以一键完成安装,而且会自动按照正确的顺序执行。
配置聚合之后,各个模块工程会在总工程中展示一个列表,让项目中的各个模块一目了然。
在总工程中配置modules即可:
pro04-maven-module
pro05-maven-module
pro06-maven-module
如果A工程依赖B工程,B工程依赖C工程,C工程又反过来依赖A工程,那么在执行构建操作时会报下面的错误:
[ERROR] [ERROR] The projects in the reactor contain a cyclic reference:
这个错误的含义是:循环引用。