1. 为什么使用Maven
Maven 还可以处理多模块项目。简单的项目,单模块分包处理即可,如果项目比较复杂,要做成多模块项目,例如一个电商项目有订单模块、会员模块、商品模块、支付模块...,一般来说,多模块项目,每一个模块无法独立运行,要多个模块合在一起,项目才可以运行,这个时候,借助 Maven 工具,可以实现项目的一键打包。
Maven是一个项目管理工具,它包含了一个项目对象模型(Project Object Model),反应在配置中,就是一个 pom.xml 文件。是一组标准集合,一个项目的生命周期、一个依赖管理系统,另外还包括定义在项目生命周期阶段的插件(plugin)以及目标(goal)。
当我们使用 Maven 的使用,通过一个自定义的项目对象模型,pom.xml 来详细描述我们自己的项目。
Maven中有两大核心:
- 依赖管理:对jar的统一管理(Maven提供了一个Maven的中央仓库,会自动取中央仓库下载相关的依赖,并且解决依赖的问题)。
- 项目构建:对项目进行编译、测试、打包、部署、上传到私服等。
2. Maven安装
-
Maven是Java项目,因此必须先安装JDK。
检查:
java -version -
下载Maven
-
配置
- 解压Maven压缩包
- 新建系统环境变量:变量名:
MAVEN_HOME,变量值:xxx\apache-maven-3.6.3 - 编辑环境变量,新增:
%MAVEN_HOME%\bin - 检查安装:
mvn -v
备注: 如果使用的IDEA,可以不用额外下载Maven,直接使用IDEA中自带的Maven插件即可。
3. Maven配置
实际上,没有特殊需求的话,安装好之后直接就可以用了。一般来说,还是需要稍微配置一下,比如中央仓库的问题。默认使用 Maven 自己的中央仓库,使用起来网速比较慢,这个时候,可以通过修改配置文件,将仓库改成国内的镜像仓库,国内仓库使用较多的是阿里巴巴的仓库。
3.1 仓库类型
| 仓库类型 | 说明 |
|---|---|
| 本地仓库 | 就是自己电脑上的仓库,默认位置在:当前用户名.m2\repository(安装Maven时可自己选择) |
| 私服仓库 | 一般来说是公司内部搭建的Maven私服,处于局域网中,访问速度快,这个仓库中存放的jar一般就是公司内部自己开发的jar |
| 中央仓库 | 有Apache团队来维护,包含了大部分的jar,早期不包含Oracle数据库驱动,从 2019 年 8 月开始,包含了 Oracle 驱动 |
Maven查找流程:
本地仓库查找 ——> 优先私服仓库(如果有的话)——> 中央仓库
3.2 本地仓库配置
本地仓库默认位置在 当前用户名.m2\repository,这个位置可以自定义,但是不建议大家自定义这个地址,有几个原因:
- 虽然所有的本地的jar都放在这个仓库中,但是并不会占用很大的空间。
- 默认的位置比较隐藏,不容易碰到。
技术上来说,当然是可以自定义本地仓库位置的,在 conf/settings.xml 中自定义本地仓库位置:
<localRepository>/path</localRepository>
3.3 远程镜像配置
由于默认的中央仓库下载较慢,因此,也可以将远程仓库地址改为阿里巴巴的仓库地址:setting.xml中
<mirror>
<id>nexus-aliyun</id>
<mirrorOf>central</mirrorOf>
<name>Nexus aliyun</name>
<url>http://maven.aliyun.com/nexus/content/groups/public</url>
</mirror>
加了这一段配置之后,就不会去Maven中央仓库上去下载依赖了,而是去阿里仓库下载,这样可以有效提高下载速度。
4. Maven常用命令
Maven中有一些常见的命令,如果使用Eclipse需要手动敲命令,如果使用IDEA的话,可以不用命令,直接点点点就可以了
| 常用命令 | 中文含义 | 说明 |
|---|---|---|
| mvn clean | 清理 | 这个命令可以用来清理已经编译好的文件 |
| mvn compile | 编译 | 将Java代码编译成Class文件 |
| mvn test | 测试 | 项目测试 |
| mvn package | 打包 | 根据用户的配置,将项目打成jar包或者war包 |
| mvn install | 安装 | 手动向本地仓库安装一个jar |
| mvn deploy | 上传 | 将jar上传到私服 |
这里需要注意的是,这些命令都不是独立运行的,它有一个顺序,举个简单例子:
我们想将jar上传到私服,那么就要构建jar,就需要执行package命令,要打包,当然也需要测试,那就要走mvn test命令,要测试就要先编译.....,因此,最终所有的命令都会执行一遍。不过,开发者也可以手动配置不执行某一个命令,这就是跳过。一般来说,除了测试,其他步骤都不建议跳过。
当然,如果开发者使用了IDEA,这些命令不用手动敲,点一下就行。
4.1 通过命令来构建项目
可以直接通过命令来构建一个 Maven 项目,不过在实际开发中,一般使用 Eclipse 或者 IDEA 就可以直接创建 Maven 项目了。
创建命令:
mvn archetype:generate -DgroupId=org.javaboy -DartifactId=firstapp -DarchetypeArtifactId=maven-archetype-quickstart -DinteractiveMode=false
看到BUILD SUCCESS表示项目创建成功:
项目创建成功后就两个文件:src和pom.xml
4.2 对项目进行打包
接下来,我们通过mvn package命令可以将刚刚创建的项目打成一个 jar 包。在打包之前,需要配置 JDK 的版本至少为 7 以上,因此,我们还需要手动修改一下 pom.xml 文件,即添加如下配置:
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>3.8.1</version>
<scope>test</scope>
</dependency>
</dependencies>
添加完成后,执行打包命令,注意执行所有命令时,命令行要定位到 pom.xml 文件所在的目录,看到如下提示,表示项目打包成功。
4.3 将项目安装到本地仓库
如果需要将项目安装到本地仓库,可以直接执行mvn install命令,注意,mvn install命令会包含上面的mvn package过程。
安装到本地仓库之后,这个时候,点开自己的本地仓库,就可以看到相关的 jar 了。
5. IDEA中使用Maven
不同于 Eclipse,IDEA 安装完成后,就可以直接使用 Maven 了。
5.1 Maven相关配置
IDEA中,Maven的配置在File -> Settings -> Build, Excution, Deployment -> Build Tools -> Maven:
5.2 JavaSE工程创建
首先在创建一个工程时,选择Maven工程:
如果勾选上 Create from archetype ,则表示可以根据一个项目骨架(项目模板)来创建一个新的工程,不过,如果只是创建 JavaSE 项目,则不用选择项目骨架。直接 Next 即可。然后填入项目的坐标,即 groupId 和 artifactId。
如:
GroupId: org.javaboy
ArtifactId: secondapp
Version: 1.0-SNAPSHOT
填完之后,直接 Next 即可。这样,我们就会获取一个 JavaSE 工程,项目结构和你用命令创建出来的项目一模一样。
5.3 JavaWeb工程创建
在IDEA中,创建Maven Web项目,有两种思路:
- 首先创建一个JavaSE项目,然后手动将JavaSE项目改造成一个JavaWeb项目
- 创建项目时选择项目骨架,骨架就选择 webapp
两种方式中,推荐使用第一种方式。
5.3.1 改造JavaSE项目
这种方式,首先创建一个JavaSE项目,创建步骤和上面一致。
项目创建完成后,首先修改pom.xml,配置项目的打包格式为war包。 这样,IDEA就知道当前项目是一个Web项目:
....
<groupId>org.javaboy</groupId>
<artifactId>secondapp</artifactId>
<version>1.0-SMAPSHOT</version>
<package>war</package>
然后,选中JavaSE工程,右键单击,选择Open Module Settings,或者直接按F4,然后选择Web,如下图:
双击webapp目录
接下来,在webapp目录中,添加web.xml文件。
注意,一定要修改web.xml文件位置:
由于默认的web.xml配置文件位置不对,所以一定要修改。
...\maven\secondapp\src\main\webapp\WEB-INF\web.xml
配置完成后,点击 OK 退出。
项目创建完成后,接下来就是部署了。
部署,首先点击IDEA右上角的Edit Configurations:
然后,配置Tomcat:Tomcat Server -> Local
点击configure配置Tomcat,直接定位到Tomcat根目录即可。
接下来选择Deployment选项卡,配置要发布的项目:
最后,点击IDEA右上角的三角符号,启动项目。
5.3.2 通过webapp骨架直接创建
这种方式比较简单,基本上不需要额外的配置,项目创建完成后,就是一个 web 项目。只需要我们在创建项目时,选择 webapp 骨架即可。
选择骨架之后,后面的步骤和前文一致。
项目创建成功后,只有webapp目录,这个时候,自己手动创建java和resources目录,创建完成后,右键单击,选择Mark Directory As,将java目录标记为sources root,将resources目录标记为resources root即可。
凡是在IDEA右下角看到了Enable Auto Import按钮,一定点一下
6. Maven依赖管理
Maven 项目,如果需要使用第三方的控件,都是通过依赖管理来完成的。这里用到的一个东西就是 pom.xml 文件,概念叫做项目对象模型(POM,Project Object Model),我们在 pom.xml 中定义了 Maven 项目的形式,所以,pom.xml 相当于是 Maven 项目的一个地图。就类似于 web.xml 文件用来描述三大 web 组件一样。
这个地图中都涉及到哪些东西呢?
6.1 Maven坐标
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.111</version>
<scope>test</scope>
</dependency>
</dependencies>
-
dependencies
在dependencies标签中,添加项目需要的jar所对应的maven坐标。
-
dependency
一个dependency标签表示一个坐标
-
groupId
团体、公司、组织结构等等的唯一标识。团体标识的约定是它以创建这个项目的组织名称的逆向域名(例如org.javaboy)开头。一个Maven坐标必须要包含groupId。一些典型的groupId如apache的groupId是org.apache。
-
artifactId
artifactId相当于在一个组织中项目的唯一标识符。
-
version
一个项目的版本。一个项目的话,可能会有多个版本。如果是正在开发的项目,我们可以给版本号加上一个SNAPSHOT,表示这是一个快照版(新建项目的默认版本号就是快照版)
-
scope
表示依赖范围
我们添加了很多依赖,但是不同依赖的使用范围是不一样的。最典型的有两个,一个是数据库驱动,另一个是单元测试。
数据库驱动,在使用的过程中,我们自己写代码,写的是JDBC代码,只有在项目运行时,才需要执行MySQL驱动中的代码。所以,MySQL驱动这个依赖在添加到项目中之后,可以设置它的scope为runtime,编译的时候不生效。
单元测试,只在测试的时候生效,所以可以设置它的scope为test,这样,当项目打包发布时,单元测试的依赖就不会跟着发布。
6.2 依赖冲突
依赖冲突产生的原因
a.jar —(依赖)—> b.jar —(依赖)—> c.jar 1.2版本
a.jar —(依赖)—> d.jar —(依赖)—> c.jar 1.4版本
在图中,a.jar 依赖 b.jar,同时 a.jar 依赖 d.jar,这个时候,a 和 b、d 的关系是直接依赖的关系,a 和 c 的关系是间接依赖的关系。
6.2.1 冲突解决
- 先定义先使用
- 路径最近原则(直接声明使用)
以spring-context为例,下图中 x 表示失效的依赖(优先级低的依赖,即路径近的依赖的优先使用):
上面这两条是默认行为。
我们也可以手动控制。手动控制主要是通过排除依赖来实现,如下:
<dependency>
<groupId>org.springframeword</groupId>
<artifactId>spring-context</artifactId>
<version>5.1.9.RELEASE</version>
<exclusions>
<exclusion>
<groupId>org.springframeword</groupId>
<artifactId>spring-core</artifactId>
</exclusion>
</exclusions>
</dependency>
这个表示从 spring-context 中排除 spring-core 依赖。
7. Maven私服
Maven仓库管理也叫Maven私服或者代理仓库。使用Maven私服有两个目的:
- 私服是一个介于开发者和远程仓库之间的代理。
- 私服可以用来部署公司自己的jar
7.1 Nexus介绍
Nexus是一个强大的Maven仓库管理工具,使用 Nexus 可以方便的管理内部仓库同时简化外部仓库的访问。官网是:www.sonatype.com/
7.2 安装
-
解压:
将下载下来的压缩包,拷贝到一个没有中文的路径下,然后解压。
-
启动:
解压之后,打开cmd窗口(以管理员身份打开cmd窗口),然后定位了nexus解压目录,执行
nexus.exe/run命令启动服务。
启动成功后,浏览器输入 http://lcoalhost:8081 打开管理页面。
打开管理页面后,点击右上角上的登录按钮进行登录,默认的用户名/密码是 admin/admin123。当然,用户也可以点击设置按钮,手动配置其他用户。
点击 Repositories 可以查看仓库详细信息:
7.2.1 仓库类型
| 名称 | 说明 |
|---|---|
| proxy | 表示这个仓库是一个远程仓库的代理,最典型的就是代理Maven中央仓库 |
| hosted | 宿主仓库,公司自己开发的一些jar存放在宿主仓库中,以及一些在Maven中央仓库上没有的jar |
| group | 仓库组,包含代理仓库和宿主仓库 |
| virtual | 虚拟仓库 |
7.2.2 上传jar
上传jar,配置两个地方:
Maven的conf/settings.xml文件配置:
<server>
<id>releases</id>
<username>admin</username>
<password>admin123</password>
</server>
<server>
<id>snapshots</id>
<username>admin</username>
<password>admin123</password>
</server>
在要上传jar的项目的pom.xml文件中,配置上传路径:
<distributionManagement>
<repository>
<id>releases</id>
<url>http://localhost:8081/repository/maven-releases/</url>
</repository>
<snapshotRepository>
<id>snapshots</id>
<url>http://localhost:8081/repository/maven-snapshots/</url>
</snapshotRepository>
</distributionManagement>
配置完成后,点击deploy按钮,或者执行mvn deploy命令就可以将jar上传到私服上。
7.2.3 下载私服上的jar
直接在项目中添加依赖,添加完成后,额外增加私服地址即可:
<repositories>
<repository>
<id>local-repository</id>
<url>http://localhost:8081/repository/maven-public/</url>
<releases>
<enabled>true</enabled>
</releases>
<snapshots>
<enabled>true</enabled>
</snapshots>
</repository>
</repositories>
8. 聚合工程
所谓的聚合工程,实际上也就是多模块项目。在一个比较大的互联网项目中,项目需要拆分成多个模块进行开发,比如订单模块、VIP 模块、支付模块、内容管理模块、CMS、CRM 等等。这种拆分方式,实际上更接近于微服务的思想。在一个模块中,还可以继续进行拆分,例如分成 dao、service、controller 等。
有人可能会说,这个分包不就行了吗?
小项目当然可以分包,大项目就没法分包了。比如,在一个大的电商系统中,有一个子模块叫做用户管理、还有一个子模块叫做订单管理,这两个子模块都涉及到用户,像这种情况,我们就需要将用户类单独提取出来,做成单独的模块,供其他模块调用。
8.1 多模块项目展示
|--javaboy-parent
|-- javaboy-cms
|-- javaboy-crm
|-- javaboy-manger
|-- javaboy-manager-model
|-- javaboy-manager-dao
|-- javaboy-manager-service
|-- javaboy-manager-web
以 javaboy-manger 为例,javaboy-manager 本身并不提供功能,它只负责管理他自己的子模块,而他的子模块每一个都无法独立运行,需要四个结合在一起,才可以运行。项目打包时,model、dao、service 都将打包成 jar,然后会自动将打包好的 jar 复制到 web 中,再自动将 web 打包成 war 包。
8.2 IDEA中创建聚合工程
-
创建一个空的Maven项目:
项目创建完成后,由于parent并不参与业务的实现,只是用来管理它的子模块,因此,src目录可以将其删除。
-
选中当前工程,右键点击,New -> Module
然后继续选中创建一个 Maven 项目
在IDEA中,已经默认指明了当前 Module 的parent,开发者值需要填入当前 Module 的 artifactId 即可:
javaboy-manage 创建完成后,此时,观察 javaboy-parent 的pom.xml文件,发现它自动加上了 packing 属性:
其中,它的packaging属性值为pom,这表示它是一个聚合工程,同时,他还多路modules及诶单,指明了它自己的模块。同时,注意javaboy-manager,它自身多了一个parent节点,这个parent节点描述了它的父模块的属性值:
<parent> <artifactId>javaboy-parent</artifactId> <groupId>org.javaboy</groupId> <version>1.0-SNAPSHOT</version> </parent>这个parent不仅仅是一个简单的父子关系描述,它存在继承关系,一般我们可以在parent中统一定义依赖或者插件的版本号
-
由于
javaboy-manager本身也是一个聚合工程,因此,javaboy-manager的src目录页可以删除 -
选中
javaboy-manager,右键单击,New -> Module 创建一个新的 Maven模块出来。这个步骤类似于第二步,不在赘述。 这里,新的 javaboy-manager-model 创建成功后,我们手动配置它的 packaging 属性值为 jar。<packaging>jar</packaging> -
依照第4步,再分别创建
javaboy-manager-service以及javaboy-manager-dao -
继续创建
javaboy-manager-web模块,不同于其他模块,web模块需要打包成war。web模块创建可以参考【第五篇文章】。 -
web工程创建完成后,完善模块之间的继承关系。
javaboy-manager-web 依赖 javaboy-manager-service javaboy-manager-service 依赖 javaboy-manager-dao javaboy-manager-dao 依赖 javaboy-manager-model
注意,依赖默认是有传递性的,即在javaboy-manager-dao中依赖了javaboy-manager-model,在javaboy-manager-service也能访问到。
配置后的依赖关系图如下:
接下来就可以在不同的模块中写代码,然后进行项目部署。
有一个需要注意的地方,在多模块项目中,web 项目打包需要注意以下问题:
-
不可以直接单独打包
-
如果要打包,有两种方式:
- 第一种就是先手动挨个将model、dao、service安装到本地仓库。
- 从聚合工程处打包,即从web的parent处打包。