Maven入门,基础概念和一些想法
2020年9月7日
21:40
1. 为什么使用Maven?
- 自动添加第三方jar包,所有项目共享jar库,提供坐标引用
- 自动解决包之间的依赖
- 规范化第三方jar包,使用同一的线上仓库管理,使用统一的接口管理
- 将项目拆分成多个工程模块,大型项目已经不是使用project或者package可以管理的了,每个模块可能需要发布在不同的服务器上
- 自动化构建,这里有非常好的例子帮助理解
其实上述环节我们在Idea中都可以找到对应的操作,只是不太标准。那么既然IDE已经可以进行构建了我们为什么还要使用Maven这样的构建工具呢?我们来看一个小故事:
这是阳光明媚的一天。托马斯向往常一样早早的来到了公司,冲好一杯咖啡,进入了自己的邮箱——很不幸,QA小组发来了一封邮件,报告了他昨天提交的模块的测试结果——有BUG。“好吧,反正也不是第一次”,托马斯摇摇头,进入IDE,运行自己的程序,编译、打包、部署到服务器上,然后按照邮件中的操作路径进行测试。“嗯,没错,这个地方确实有问题”,托马斯说道。于是托马斯开始尝试修复这个BUG,当他差不多有眉目的时候已经到了午饭时间。 下午继续工作。BUG很快被修正了,接着托马斯对模块重新进行了编译、打包、部署,测试之后确认没有问题了,回复了QA小组的邮件。 一天就这样过去了,明媚的阳光化作了美丽的晚霞,托马斯却觉得生活并不像晚霞那样美好啊。 |
让我们来梳理一下托马斯这一天中的工作内容
从中我们发现,托马斯的很大一部分时间花在了“编译、打包、部署、测试”这些程式化的工作上面,而真正需要由“人”的智慧实现的分析问题和编码却只占了很少一部分。
能否将这些程式化的工作交给机器自动完成呢?——当然可以!这就是自动化构建。
那么Maven又是如何实现自动化构建的呢?简单的说来就是它可以自动的从构建过程的起点一直执行到终点:
2. Maven的基本使用
创建Maven项目之后,整个项目的依赖由Maven管理,我们只需要在pom.xml下配置依赖jar包的相关信息。例如,以下是一个典型的pom.xml。只使用xml相关的基础知识便能够看到,下边的dependencies即配置了相关的依赖,上边的gropId,artifactId,version则是本项目的相关属性。
使用maven之后的效果是,可以让maven进行自动部署,包括一系列自动化的流程。
maven是一套管理jar的工具,单看一个项目并无法切实体会到它的方便,但可想而知,当模块变成几千个几万个的时候,自动化过程是极其重要的。
3. Maven的基础概念
3.1 POM, Project Object Model
maven的核心文件,其实操作maven也就是编写POM文件的过程。在Maven的世界里,每个Jar都是一个对象,这个pom文件显而易见就是对象配置文件。
有时候比较神奇,从这个角度来看,仿佛这整一套maven就是为了服务这个pom文件的——过于简单,但是却异常有用。
现在JavaEE开发领域普遍认同一个观点:约定>配置>编码。想想确实非常有道理。
3.2 唯一标识,坐标
所有jar都以以下三个名字标识,三者可以合成本地库的目录,这也非常自然。
groupId:公司或组织的域名倒序+当前项目名称
artifactId:当前项目的模块名称
version:当前模块的版本
3.3 依赖管理
大型工程以模块作为单位,模块之下又有许多模块,我们总不想在每个模块都存入同样的的jar包,各个模块之间的jar包版本又如何解决?这也是Maven存在的意义——统一管理,提供坐标给出引用。
但就类似在代码中include,import,多个文件引用必定形成引用链,这时候就会出现很多问题,例如,版本冲突如何解决,祖先节点引用过的我能不声明吗?祖先节点引用的版本太老,不想引用怎么办?
这种引用链非常常见,这也是Maven理所当然应该解决的问题。所以Maven的复杂之处,大半就在这里。
3.3.1 Scope
依赖可以声明范围,运行时,测试时,编译时的范围被界定开来。如下图。
这图比较乱,主要知道compile范围可以在所有时候使用,test最小,只能在test时使用(不可再main中使用到test scope的jar)
- compile
[1]main目录下的Java代码可以访问这个范围的依赖
[2]test目录下的Java代码可以访问这个范围的依赖
[3]部署到Tomcat服务器上运行时要放在WEB-INF的lib目录下
例如:对Hello的依赖。主程序、测试程序和服务器运行时都需要用到。
- test
[1]main目录下的Java代码不能访问这个范围的依赖
[2]test目录下的Java代码可以访问这个范围的依赖
[3]部署到Tomcat服务器上运行时不会放在WEB-INF的lib目录下
例如:对junit的依赖。仅仅是测试程序部分需要。
- provided
[1]main目录下的Java代码可以访问这个范围的依赖
[2]test目录下的Java代码可以访问这个范围的依赖
[3]部署到Tomcat服务器上运行时不会放在WEB-INF的lib目录下
例如:servlet-api在服务器上运行时,Servlet容器会提供相关API,所以部署的时候不需要。
3.3.2 冲突管理原则
最短依赖优先,先声明优先。
依赖可以使用exclusion关键字排除。
<dependency>
<groupId>com.atguigu.maven</groupId>
<artifactId>OurFriends</artifactId>
<version>1.0-SNAPSHOT</version>
<!--依赖排除-->
<exclusions>
<exclusion>
<groupId>commons-logging</groupId>
<artifactId>commons-logging</artifactId>
</exclusion>
</exclusions>
</dependency>
3.3.4 版本统一管理
变量
pom大了以后,引用得多,版本不好管理,可以把version单独抽出来,就像一个局部变量一样,这也没什么。
<properties>
<spring.version>4.0.0.RELEASE</spring.version>
</properties>
实际上,依赖管理还有一个重要的实现,继承,但是内容比较多,以下讲解。
继承
另一个方法是继承,专门把各种jar都交给父工程来管理,子类就不需要再管版本问题了,以下是用法。
父工程中声明:
<dependencyManagement>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.0</version>
<scope>test</scope>
</dependency>
</dependencies>
</dependencyManagement>
子工程继承:
<parent>
<groupId>com.atguigu.maven</groupId>
<artifactId>Parent</artifactId>
<version>1.0-SNAPSHOT</version>
<!--指定从当前pom.xml文件出发寻找父工程的pom.xml文件的相对路径-->
<relativePath>../Parent/pom.xml</relativePath>
</parent>
3.4 聚合
聚合就组合,多个工程分别执行自动化流程太麻烦,于是可以将其封装成一个大模块。
<modules>
<module>../MakeFriend</module>
<module>../OurFriends</module>
<module>../HelloFriend</module>
<module>../Hello</module>
</modules>