【JAVA项目管理】【Maven】一篇搞定maven
一、什么是Maven
Maven是Apache下的一个纯Java开发的开源项目,是一个项目管理工具,用于构建和管理任何基于java的项目:
- 构建:Maven通过一套统一标准的构建方法来构建maven项目,并明确定义项目的组成结构。
- 管理:Maven根据其生命周期去管理项目,包括依赖、测试、打包、发布等;可以实现多个项目共享jar包。
Maven提供仓库管理、依赖管理、插件拓展、继承和聚合等特性为项目的构建和管理提供了一整套完善的解决方案。
二、Maven使用场景
- 希望统一的方式构建java项目(提供项目统一的目录结构)
- 需要项目jar包的统一管理,依赖管理(提供项目仓库管理)
- 希望能对项目进行快速的编译、测试、打包等操作(提供项目生命周期管理)
- 还可以进行插件拓展,如自己开发的maven插件专门对java项目代码规范扫描也可以集成到maven中,可以使用该插件在项目打包之前进行项目扫描(提供插件辅助项目开发)
三、Maven安装使用流程
- 前提条件
maven是纯java开发的项目管理工具,因此需要安装JDK,配置JDK环境变量。
- 安装:
- 根据JDK版本下载对应的Maven版本:
- https://maven.apache.org/docs/history.html (版本对照说明)
- https://archive.apache.org/dist/maven/maven-3/ (下载对应版本,下载二进制文件zip或者tar.gz都可以)
- 解压zip或tar.gz包到指定目录(安装目录)
- 将安装目录里面的bin目录路径,配置添加到path环境变量中即可。
- 最后在终端输入命令:mvn -v 验证返回maven版本信息即表示安装成功。
- 配置maven的本地仓库:在安装目录找到settings.xml配置文件,修改<localRepository></localRepository>标签即可。
- 在IDEA中配置使用Maven:IDEA现在都自带Maven,我们可以根据需要使用自己安装的Maven或者保留修改自带的也行。
- 使用流程(项目构建)
项目构建包含源代码的编写、编译、测试、运行、打包、部署、运行的过程。
- 传统的项目构建过程:
- 在开发工具如IDEA中创建一个java工程
- 在工程中编写源代码及配置文件
- 对源代码进行编译(将java源文件编译成class文件)
- 执行Junit进行单元测试
- 将工程打成jar包或者war包部署运行
- maven的项目构建过程(一般过程):
- 在开发工具如IDEA新建一个maven项目,并编写java源代码。
- 清除阶段:mvn clean,清除所有class文件。
- 编译阶段:mvn compile,将java源代码编译成class文件
- 测试阶段:mvn test,执行单元测试
- 打包阶段:mvn package,将java工程打包成jar包或war包
- 安装本地仓库阶段:mvn install,将打包好的jar/war包安装到本地仓库
- 发布远程仓库阶段:mvn deploy,将打包好的jar/war包发布上传到远程仓库
每执行一个阶段都会把前面的阶段按顺序执行;使用Maven构建项目的优势:统一命令完成项目生命周期管理,规范项目构建,方便管理和团队协作。
注意打包阶段的两点问题:
- 第一:src/main下内容最终会打包到Jar/War中,而src/test下是测试内容,并不会打包进去。
- 第二:src/main/resources中的资源文件会COPY至目标目录,这是Maven的默认生命周期中的一个规定动作。(想一想,hibernate/mybatis的映射XML需要放入resources下,而不能在放在其他地方了)
四、Maven仓库管理
maven仓库分为两种类型:本地仓库和远程仓库。
- 本地仓库:是指在安装Maven后创建在本机的仓库,maven运行项目构建所需要的jar包都是来自本地仓库,如果没有所需的jar包先去远程仓库下载到本地仓库。涉及本地仓库的几种场景:
- settings.xml本地仓库配置:
<localRepository>/path/to/local/repo</localRepository>
- 若本地和远程仓库都没有所需的jar包/pom文件,则需要手动找到jar包/pom文件后install到本地仓库:
- 手动安装jar包:
mvn install:install-file -Dfile=<path-to-file> -DgroupId=<group-id> -DartifactId=<artifact-id> -Dversion=<version> -Dpackaging=<package_name>
- 手动安装pom文件(maven-install-plugin插件版本2.5以上):
mvn install:install-file -Dfile=<path-to-file> -DpomFile=<path-to-pomfile>
- 安装好在本地仓库的jar包或pom文件后,需要上传到远程仓库,已达到开发共享:
mvn deploy:deploy-file -DgroupId=<group-id> \
-DartifactId=<artifact-id> \
-Dversion=<version> \
-Dpackaging=<type-of-packaging> \
-Dfile=<path-to-file> \
-DrepositoryId=<id-to-map-on-server-section-of-settings.xml> \
-Durl=<url-of-the-repository-to-deploy>
或者使用pom文件定义需要上传包的groupId,artifactId,version和packaging等信息,使用下面命令:
mvn deploy:deploy-file -DpomFile=<path-to-pom> \
-Dfile=<path-to-file> \
-DrepositoryId=<id-to-map-on-server-section-of-settings.xml> \
-Durl=<url-of-the-repository-to-deploy>
- 远程仓库:分为私服仓库和中央仓库,可以配置多个远程仓库,在setting.xml或pom.xml都可以配置。
- 私服仓库:就是自己工作开发或公司内部自己搭建的一个局域网共享仓库服务器。
- 中央仓库:是由第三方提供的远程仓库,默认为maven仓库id=central,不需要配置(https://repo.maven.apache.org/maven2/)。
使用远程仓库的优点:使用远程仓库,提高开发者之间的交互;配置多个远程仓库,减少对依赖下载的压力,提高性能和构建稳定性。配置多个远程仓库涉及在以下地方:
- 子项目pom.xml/父项目pom.xml文件(私服仓库):
<project>
...
<repositories>
<repository>
<id>Remove Repo id1</id><!--远程仓库的ID-->
<name>Remove Repo name1</name><!--远程仓库的名称-->
<url>http://Remove Repo Addr1</url><!--远程仓库的url地址-->
</repository>
<repository>
<id>Remove Repo id2</id><!--远程仓库的ID-->
<name>Remove Repo name2</name><!--远程仓库的名称-->
<url>http://Remove Repo Addr2</url><!--远程仓库的url地址-->
</repository>
</repositories>
...
</project>
- Maven全局/用户配置文件settings.xml(私服仓库):
<settings>
...
<profiles>
...
<profile>
<id>myprofile</id>
<repositories>
<repository>
<id>Remove Repo id2</id><!--远程仓库的ID-->
<name>Remove Repo name2</name><!--远程仓库的名称-->
<url>http://Remove Repo Addr2</url><!--远程仓库的url地址-->
</repository>
</repositories>
</profile>
...
</profiles>
<!--需要激活才能使用该远程仓库-->
<activeProfiles>
<activeProfile>myprofile</activeProfile>
</activeProfiles>
...
</settings>
- Maven全局配置文件settings.xml(远程仓库镜像,代理作用):
<settings>
...
<mirrors>
<mirror>
<!--镜像服务的ID-->
<id>other-mirror</id>
<!--镜像服务的名称-->
<name>Other Mirror Repository</name>
<!--仓库镜像代理匹配条件:根据上面pom.xml或者settings.xml配置依赖jar包下载的远程仓库id匹配-->
<!--匹配通配符有:'*'匹配所有远程仓库,'external:*'匹配除了本地文件的所有远程仓库,'repo,repo1'匹配指定远程仓库,'*,!repo1'匹配除了repo1的所有远程仓库-->
<mirrorOf>central</mirrorOf>
<!--当匹配条件成立时,会跳转到该URL地址做代理完成jar下载-->
<url>https://other-mirror.repo.other-company.com/maven2</url>
</mirror>
</mirrors>
...
</settings>
maven仓库依赖大概访问顺序:本地仓库(local)--> 远程仓库(私服) --> 远程仓库(中央仓库)
依赖具体访问顺序:local_repo --> settings_profile_repo($Maven_HOME/conf/settings > $User_home/conf/settings) -->pom_repostitorues(多个仓库按声明倒序) --> settings_mirrors --> central
三者的关系:
五、Maven依赖管理
Maven项目依赖的第三方项目jar包,通过maven规范化管理:在pom.xml文件中配置,maven运行时会自动从maven仓库(上面三大仓库)中查找下载。
- 传统项目的依赖管理:
- 手工从网上下载所依赖的jar包到本地
- 手工拷贝jar包并添加到java工程中。
- 容易造成jar包的版本冲突的问题
- 网上人工查找依赖包费时、效率低,直接拷贝添加到工程中会导致工程体积过大等问题。
- Maven项目的依赖管理:
- 通过maven仓库统一存储依赖包,方便查找、自动下载与使用。
- 通过pom.xml统一版本依赖管理,使用groupId、artifactId、version进行jar包版本坐标定位,减少版本冲突。
- maven可以平台使用,方便快捷。
- 具体使用
在pom.xml配置文件中使用标签<dependency></dependency>来依赖第三方jar包,使用坐标:groupId、artifactId、version来定位具体版本
<dependency>
<groupId>servlet-api</groupId>
<artifactId>servlet-api</artifactId>
<version>2.5</version>
<scope>system</scope>
<systemPath>${project.basedir}/libs/servlet-api-2.5.jar</systemPath>
</dependency>
- 依赖传递:如果A依赖B,B依赖C,那么引入A,意味着B和C都会被引入。
- Maven的最近依赖策略:如果一个项目依赖相同的groupId、artifactId的多个版本,那么在依赖树(mvn dependency:tree)中离项目最近的那个版本将会被使用。(Gradle用的是version+策略)
- 解决依赖冲突
- 方式1:要使用哪个版本,我们是清楚的,不管如何依赖传递,可以进行版本锁定
使用<dependencyManagement> [这种主要用于子模块的版本一致性中]
- 方式2:在依赖传递中,去掉我们不想依赖的。
使用<exclusions> [在实际中我们可以在IDEA中直接利用插件帮助我们生成]
- 方式3:最近依赖策略,我们就直接使用显式依赖指定版本。
使用<dependency>
如果我们新加入一个依赖的话,那么先通过mvn dependency:tree命令形成依赖树,看看我们新加入的依赖,是否存在传递依赖,传递依赖中是否和依赖树中的版本存在冲突,如果存在多个版本冲突,利用上面的方式进行解决!
六、Maven生命周期
执行后面的命令时,前面的命令自动得到执行。实际上,我们最常用的就是这么几个:
- clean:有问题,多清理!
- package:打成Jar or War包,会自动进行clean+compile
- install:将本地工程Jar上传到本地仓库
- deploy:上传到私服
七. scope依赖范围
既然,Maven的生命周期存在编译、测试、运行这些过程,那么显然有些依赖只用于测试,比如junit;有些依赖编译用不到,只有运行的时候才能用到,比如mysql的驱动包在编译期就用不到(编译期用的是JDBC接口),而是在运行时用到的;还有些依赖,编译期要用到,而运行期不需要提供,因为有些容器已经提供了,比如servlet-api在tomcat中已经提供了,我们只需要的是编译期提供而已。总结来说:
- compile:默认的scope,运行期有效,需要打入包中。
- provided:编译期有效,运行期不需要提供,不会打入包中。
- runtime:编译不需要,在运行期有效,需要导入包中。(接口与实现分离)
- test:测试需要,不会打入包中。
- system:非本地仓库引入、存在系统的某个路径下的jar。(一般不使用)
- 点赞
- 收藏
- 关注作者
评论(0)