Maven
是一个项目管理工具,它的本质是一个 项目对象模型(POM) ,体现在配置中就是我们常见的 pom.xml
文件,而这个 pom
文件就是 Maven
的核心,它管理了整个项目的生命周期。它主要做两件事:
Maven
诞生时就提出了一个仓库的概念,项目中用到的第三方 jar
包,我们在 pom.xml
中配置好依赖即可, Maven
会自动到它的官方中央仓库下载这个 jar
包到我们的本地仓库。 Java
发展至今,生态非常完善。我们在项目中用到什么功能,网上一搜肯定有对应的 jar
包,各种功能就导致了各种 jar
包的引入,这些 jar
包之间可能会有依赖,可能会有版本冲突。而 Maven
的诞生解决了这些问题。 Maven
的一键构建项目帮我们解决了这个问题。 maven
的时代,团队协作要上传、下载一大堆 jar
包导入项目,耗时、费力。而有了 maven
,我们只需要同步一下 pom
文件即可同步 jar
包。这是 maven
解决的第三个问题。 这个就不讲了,网上很多资料。比如: https://www.cnblogs.com/KyleXu/p/9972042.html
Maven
的配置比较简单,主要是修改 conf
文件夹下的 setting
文件。配置以下三个仓库:
项目依赖的 jar
包是需要下载到本地才能用的。本地仓库就是从 maven 私服或者远程仓库下载的 jar
的存储地址,默认是 当前用户名/.m2/repository
,我建议改个好记的地方,后面方便检查包有没下载到本地。打开 setting.xml
搜索 localRepository
修改成自定义的地址。
<localRepository>D:/Repository</localRepository>
配置的位置,如下图:
这个仓库的话,一般就是公司内部使用的啦。用来存储公司内部自己的 jar
包。打开 setting.xml
文件搜索 mirrors
,配置公司的镜像地址即可。
<mirror> <id>nexus-repos</id> <mirrorOf>*</mirrorOf> <name>Team Nexus Repository</name> <url>http://127.0.0.1:8081/nexus/content/groups/public</url> </mirror>
远程仓库就是一个 maven
官方维护的,包含大量 jar
包的仓库。这个库默认是 maven 官方的,但是下载非常慢。所以业界典范阿里巴巴也推出了一个国内的镜像,我们一般把远程仓库配成阿里的镜像地址,就可以快速地下载 jar
包啦。和私服仓库一样,远程仓库也是配置在 <mirrors>
标签内。
<mirror> <id>alimaven</id> <name>aliyun maven</name> <url>http://maven.aliyun.com/nexus/content/groups/public/</url> <mirrorOf>central</mirrorOf> </mirror>
配置的位置,如下图:
有人可能问了,配置那么多个仓库。究竟 jar
从哪个下载的呀?都把我搞糊涂了,别急,我花了个流程图,它的查找顺序是这样的:本地不需要网络,优先从本地找;找不到,再去速度较高的内网私服找;然后才是速度稍低的外网远程仓库找。
命令 | 含义 | 备注 |
---|---|---|
mvn clean | 清除 | 打包前,清空上一次的包 |
mvn compile | 编译 | 将 java 代码编译成 class 文件 |
mvn test | 测试 | 运行单元测试 |
mvn install | 安装到本地 | 安装到本地仓库,一般是 jar 包 |
mvn package | 打包 | 一般会在 target 目录下生成包,jar 或 war |
mvn deploy | 上传 | 上传到私服,需在 setting.xml 文件配置私服仓库以及账号密码 |
以上就是 maven
常用的命令,要注意的是:很少情况下我们只运行其中一个命令,都是组合运行的。比如打包到本地,打包前得清空原有的包吧?那组合起来就是 mvn clean
+ mvn install
当然,在 IDEA
中开发 maven
项目,我们并不需要手打。只需点击对应命令即可(也可以按住 ctrl
选中多个命令一起运行)
总而言之,根据自己的需求来选择打包命令。还有其他的命令请见:
现在一般都是配合 idea
新建 maven 项目了,这个命令用得很少,但我们还是得知道一下:生成 maven
项目的原理是,依赖一个插件 maven-archetype-plugin
,然后这个插件自带一些 archetype
模版,也可以说成项目的骨架。其中: -DgroupId
和 -DartifactId
填写自己想好的项目坐标,一般 -DgroupId
是公司名的翻转,比如 com.google
而 -DartifactId
就是项目的名称了。最重要的是 -DarchetypeArtifactId
,他指定了创建的骨架。
mvn archetype:generate -DgroupId=com.nasus -DartifactId=maven-test -DarchetypeArtifactId=maven-archetype-quickstart -DinteractiveMode=false
点进去,只有 src
文件夹和 pom.xml
文件: src
是最重要的目录,代码和测试用例以及资源都是放在这里的,对于 maven 项目而言, pom.xml
也是必不可少的。
用 idea
打开的项目结构是这样的:
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/maven-v4_0_0.xsd"> <!--声明项目描述符遵循哪一个 POM 模型版本,上面的 xsd 规范定义了这个版本,默认就行,不需要修改,不可删除--> <modelVersion>4.0.0</modelVersion> <!--团体唯一标识符--> <groupId>com.nasus</groupId> <!--项目唯一标识符定位这个包--> <artifactId>maven-test</artifactId> <!--打包类型--> <packaging>jar</packaging> <!--打包版本--> <version>1.0-SNAPSHOT</version> <!--包名--> <name>maven-test</name> <!--不用管,删掉也行--> <url>http://maven.apache.org</url> <!--项目需要依赖的 jar 包--> <dependencies> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>3.8.1</version> <scope>test</scope> </dependency> </dependencies> </project>
由于篇幅原因,这里就不详细讲具体的 pom.xml
标签了,详细介绍请看:
由于项目是 java
项目,在打包前,我们要在 pom.xml
中配置项目的 JDK
版本以及 maven
插件版本,在 <dependencies>
标签前加入 项目属性 配置,完整配置如下:
<!--项目属性,在 <dependencies> 前加--> <properties> <!-- JDK编译版本 --> <java.version>1.8</java.version> <!-- 项目编码 --> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <!-- JDK编译版本 --> <maven.compiler.source>1.8</maven.compiler.source> <maven.compiler.target>1.8</maven.compiler.target> <maven.compiler.compilerVersion>1.8</maven.compiler.compilerVersion> </properties> <!--项目需要依赖的 jar 包--> <dependencies> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>3.8.1</version> <scope>test</scope> </dependency> </dependencies>
选择命令,这里我选了 clean、compile、package
:
点击绿色执行按钮,在 target
目录下生成 maven-test-1.0.SNAPSHOT.jar
:
在开发中,我们经常需要本地测试,而这时我们是不需要跑单元测试的。所以,我们可以跳过单元测试:选中 test
,点击红框按钮即可。
手动打 jar
包的应用场景是:开发公司旧项目,当找不到依赖的 jar
源码,依赖的 jar
又没有上传到仓库,只有在同事电脑的本地仓库有一个 jar
包时,我们可以直接运行这条命令把 jar
包打到我们电脑本地仓库,愉快的使用起来。
mvn install:install-file -Dfile=jar包的路径 -DgroupId=gruopId中的内容 -DartifactId=actifactId的内容 -Dversion=version的内容 -Dpackaging=jar
maven 通过 pom.xml 来进行依赖管理,我们用它来描述项目的依赖属性。可以把它看作是 maven 项目的地图,它描述了 jar 包的坐标、版本以及依赖关系等。如果不确定你想要引入 jar 的坐标怎么写,可以上 maven 中央仓库查询:
maven 的第三方依赖都在 <dependencies>
标签内定义,该标签下的 <dependency>
包裹的内容就是一个 jar
的坐标,如下 pom 就引入了 junit
和 cglib
两个 jar
。下面就说一下每个坐标的标签都代表什么。
<dependencies> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.11</version> <scope>test</scope> </dependency> <dependency> <groupId>cglib</groupId> <artifactId>cglib</artifactId> <version>3.3.0</version> </dependency> </dependencies>
在 dependencies 标签中,添加项目需要的 jar 所对应的 maven 坐标。
一个 dependency 标签表示一个坐标,也就是一个 jar,在 pom 中引入一个 jar 可以这样写:
<dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.11</version> <scope>test</scope> </dependency>
公司、团体、个人开发者的唯一标识符,maven 约束它以创建这个项目的组织名称的逆向域名开头,比如开发者的域名是 nasus.com
那他的唯一标识符就是 com.nasus
。
<!--团体唯一标识符--> <groupId>com.nasus</groupId>
项目唯一标识符,一个组织可能有多个项目,为了方便 maven 引入,maven 约定以项目名称命名该标识符,比如我开发的 maven-test 项目。
<!--项目唯一标识符--> <artifactId>maven-test</artifactId>
项目的版本。一个项目,可能会有多个版本。如果是正在开发的项目,我们可以给版本号加上一个 SNAPSHOT,表示这是一个快照版本。
对于版本,如果 maven
以前下载过指定的版本文件,比如说 maven-test:1.0
, maven
将不会再从仓库下载新的可用的 1.0
文件。若要下载更新的代码, maven-test
的版本需要升到 1.1
。
快照是一种特殊的版本,指定了某个当前的开发进度的副本。不同于常规的版本, maven
每次构建都会在远程仓库中检查新的快照。我们自己的模块依赖了同事开发的模块,正常来说,同事会每次发布更新代码的快照到仓库中。
新建项目的默认版本号就是快照版,比如上面用 maven 命令新建的 maven-test 项目:
maven 项目不同的阶段引入到 classpath 中的依赖是不同的,例如,编译时,maven 会将与编译相关的依赖引入 classpath 中,测试时,maven 会将测试相关的的依赖引入到 classpath 中,运行时,maven 会将与运行相关的依赖引入 classpath 中,而依赖范围就是用来控制依赖于这三种 classpath 的关系。 如下图所示:
scope 表示依赖的范围,它有 compile(编译阶段)、test(测试阶段)、provided(供应阶段)、runtime(运行阶段)、system(系统阶段)、import(导入阶段)
六个可选值。其中 compile
是默认的。 system
和 import
用得少,不详细讲。
不同依赖的适用范围不一样,举几个最典型的栗子:
范围 | 编译有效 | 测试有效 | 运行时有效 | 打包有效 | 示例 |
---|---|---|---|---|---|
compile | 是 | 是 | 是 | 是 | spring-core |
test | 否 | 是 | 否 | 否 | junit |
provided | 是 | 是 | 否 | 否 | javax.servlet-api |
runtime | 否 | 是 | 是 | 是 | JDBC驱动 |
spring-core
servlet-api
编译和测试项目的时候需要该依赖,但在运行项目的时候,由于容器已经提供,就不需要 maven
重复地引入一遍: <dependency> <groupId>javax.servlet</groupId> <artifactId>javax.servlet-api</artifactId> <version>3.1.0</version> <scope>provided</scope> </dependency>
<dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.11</version> <scope>test</scope> </dependency>
<dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>8.0.12</version> <scope>runtime</csope> </dependency>
如下 xml,原来的定义中已引入 commons-net
依赖,而 hermes-ftp
中又依赖了 commons-net
,为避免版本冲突,我们可以排除 hermes-ftp
中的 commons-net
依赖。
<dependency> <groupId>commons-net</groupId> <artifactId>commons-net</artifactId> <version>3.6</version> </dependency> <dependency> <groupId>com.nasus.greece.jupiter</groupId> <artifactId>hermes-ftp</artifactId> <version>1.1.0-SNAPSHOT</version> <!--排除 commons-net 依赖--> <exclusions> <exclusion> <artifactId>commons-net</artifactId> <groupId>commons-net</groupId> </exclusion> </exclusions> </dependency>
假设有如下项目关系: WebMavenDemo
项目依赖 JavaMavenService1
, JavaMavenService1
项目依赖 JavaMavenService2
。
pom.xml 文件配置好依赖关系后,必须首先 mvn install 后,依赖的 jar 包才能使用。比如:
WebMavenDemo
的 pom.xml
文件想能编译通过, JavaMavenService1
必须 mvn install
JavaMavenService
的 pom.xml
文件想能编译通过, JavaMavenService2
必须 mvn install
假设我们现在 JavaMavenService2
增加 spring-core
,那就会发现 WebMavenDemo
和 JavaMavenService1
也会自动的增加了这个 jar
包,这就是依赖的传递性。
注意:非 compile
范围的依赖是不能传递的。
在上面介绍 pom 文件时,我们讲过 properties
标签,它还有一个作用就是限定依赖的 jar 包版本,它常用在父项目中指定版本号,那么子项目用到该包就避免了版本不一致造成的依赖冲突,它的写法是这样的:
maven 打 war 包时,可能需要一些额外的配置,请参看以下 xml 文件:
<build> <!-- 项目的名字 --> <finalName>maven-test</finalName> <!-- 描述项目中资源的位置 --> <resources> <!-- 自定义资源1 --> <resource> <!-- 资源目录 --> <directory>src/main/java</directory> <!-- 包括哪些文件参与打包 --> <includes> <include>**/*.xml</include> </includes> <!-- 排除哪些文件不参与打包 --> <excludes> <exclude>**/*.txt</exclude> <exclude>**/*.doc</exclude> </excludes> </resource> </resources> <!-- 设置构建时候的插件 --> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> <version>2.1</version> <configuration> <!-- 源代码编译版本 --> <source>1.8</source> <!-- 目标平台编译版本 --> <target>1.8</target> </configuration> </plugin> <!-- 资源插件(资源的插件) --> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-resources-plugin</artifactId> <version>2.1</version> <executions> <execution> <phase>compile</phase> </execution> </executions> <configuration> <encoding>UTF-8</encoding> </configuration> </plugin> <!-- war插件(将项目打成war包) --> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-war-plugin</artifactId> <version>2.1</version> <configuration> <!-- war包名字 --> <warName>maven-test</warName> </configuration> </plugin> </plugins> </build>
这个网上很多资料,不讲了。留个链接。
如果看到这里,喜欢这篇文章的话,请转发、点赞。微信搜索「 一个优秀的废人 」,欢迎关注。
回复「 1024 」送你一套完整的 java、python、c++、go、前端、linux、算法、大数据、人工智能、小程序以及英语教程。
回复「 电子书 」送你 50+ 本 java 电子书。