前言
Maven是跨平台的项目管理工具。主要服务于基于Java平台的项目构建,依赖管理和项目信息管理。接下来我们就来介绍一下项目构建和依赖管理。
一个使用Maven管理的普通的Java项目,它的目录结构默认如下:
maven-project
|—— src
| |—— main
| | |—— java
| | |—— resources
| |—— test
| |—— java
| |—— resources
|—— pom.xml
|—— target
maven-project 是项目名, pom.xml 是项目描述文件,存放 Java 源码的目录是 src/main/java,存放资源文件的目录是 src/main/resources,存放测试源码的目录是 src/test/java,存放测试资源的目录是src/test/resources,最后,所有编译、打包生成的文件都放在target目录里。这些就是一个 Maven 项目的标准目录结构。
一、安装 Maven
Maven 是 Apache 基金会的顶级项目,我们可以从 http://maven.apache.org/ 下载 Maven 开发包,其实就是一个压缩包,下载完毕后,解压一下,配置一下环境变量就可以用了。
假设我们刚刚下载了一个 apache-maven-3.6.3-bin.tar.gz 文件,现在将其解压到 C:/maven 目录下 。这样 Maven 的根目录就是 C:\maven\apache-maven-3.6.3 了。
配置环境变量:
MAVEN_HOME = C:\maven\apache-maven-3.6.3
PATH: %MAVEN_HOME%\bin
最后我们可以打开 cmd,输入 mvn -v 进行验证
二、Maven 仓库
使用 Maven 给我们带来的最直接的帮助,就是 jar 包得到了统一管理,那么这些 jar 包存放在哪里呢?它们就在您的 本地仓库 中,位于 C:\Users\ 用户名 .m2 目录下(可以通过 settings.xml 修改本地仓库地址)。
实际上可将本地仓库理解 " 缓存 ",因为项目首先会从本地仓库中获取 jar 包,当无法获取指定 jar 包的时候,本地仓库会从远程仓库中下载 jar 包,并放入本地仓库中以备将来使用。
maven仓库的分类:本地仓库和远程仓库。其中远程仓库包括中央仓库、私服和其他公共库。
三、了解 pom.xml
pom 的英文全拼为 Project Object Model ,项目对象模型。通过 xml 可扩展标记语言格式保存 pom.xml 文件,功能更强大。该文件可用于管理:源代码、配置文件、开发者的信息和角色、问题追踪系统、组织信息、项目授权、项目的 url 、项目的依赖关系等。
1、头标签信息
<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/xsd/maven-4.0.0.xsd">
</project>
- xmlns:命名空间,类似包名,因为 xml 的标签可以自定义,需要命名空间来定位。
- xmlns:xsi:xml 需要遵循的标签规范。
- xsi:schemaLocation:用来定义xml schemaLocation 的地址,也就是 xml 书写时需要遵循的语法。
2、maven 的基本信息
<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/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com</groupId>
<artifactId>SpringBoot</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>jar</packaging>
<name>myName</name>
<url>www.funtl.com</url>
</project>
- modelVersion:声明项目描述遵循哪一个 POM 模型版本。模型本身的版本很少改变,虽然如此,但他仍然是必不可少的,这是为了当 Maven 引入新的特性或者其他模型变更的时候,确保稳定性。
- groupId :公司或组织的唯一标识。
- artifactId:本项目的唯一 ID ,一个 groupId 下面可能有多个项目,就是靠 artifactld 来区分的。
- version:本项目目前所处的版本号
- packaging:打包类型,可取值:pom、jar、war、ejb、par、rar、ear、maven-plugin。
- name:项目的名称,maven 产生的文档需要用到,可省略。
- url:项目主页的 url ,maven 产生的文档需要用到,可省略。
3、POM 之间的关系
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.0</version>
<scope>test</scope>
<optional>true</optional>
<exclusions>
<exclusion>
<groupId>xxx</groupId>
<artifactId>xxx</artifactId>
</exclusion>
</exclusions>
</dependency>
</dependencies>
- groupId:依赖项的组织名。
- artifactId:依赖项的子项目名。
- version:依赖项的版本。
- scope:依赖项的适用范围 ,包括 compile、provided、runtime、test、system 和 exclusions
- optional:可选依赖,如果你在项目 B 中把 C 依赖声明为可选,你就需要在依赖于 B 的项目(例如项目 A )中显式的引用对 C 的依赖。
- exclusions:排除项目中的依赖冲突时使用,不依赖该项目。
- type 依赖类型一般省略,默认类型是 jar,其他还有 jar、war、ejb-client 和 test-jar。
scope 依赖项的适用范围
- compile:缺省值,适用于所有阶段,会随着项目一起发布。
- provided:类似于 compile,期望 JDK、容器或使用者会提供这个依赖,如:servlet.jar。
- runtime:只在运行时使用,如 JDBC 驱动,不会随项目发布。
- system:类似 provided,需要显示提供包含依赖的 jar, Maven不会在 Repository 中查找它。
- optional:当项目自身被依赖时,标注依赖是否传递,用于连续依赖时使用。
从上往下简要说明一下:
4、Maven 的六类属性
下面开始介绍
4.1、maven 内置属性
- ${basedir} :项目的根目录(包含 pom.xml 文件的目录)。
- ${version}: 项目版本。
4.2、pom 属性
- ${project.build.sourceDirectory}:项目的主源码目录,默认为 src/main/java
- ${project.build.testSourceDirectory}:项目的测试源码目录,默认为 src/test/java
- ${project.build.directory}:项目构件输出目录,默认为 target/
- ${project.outputDirectory}:项目主代码编译输出目录,默认为 target/classes/
- ${project.testOutputDirectory}:项目测试代码编译输出目录,默认为 target/test-classes/
- ${project.groupId}:项目的 groupId
- ${project.artifactId}:项目的 artifactId
- ${project.version}:项目的 version,与 ${version} 等价
- ${project.build.fianlName}:项目打包输出文件的名称,默认为 " ${project.artifactId} - ${project.version} "
4.3、自定义属性
<!--配置依赖版本-->
<properties>
<!-- Environment Settings -->
<java.version>1.8</java.version>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<!-- Spring cloud Settings -->
<spring-cloud.version>Finchley.RELEASE</spring-cloud.version>
<spring-boot-admin.version>2.0.1</spring-boot-admin.version>
<zipkin.version>2.10.1</zipkin.version>
</properties>
用户可以在 pom 的元素下自定义 Maven 属性,然后我们可以在 pom 文件中通过 ${zipkin.version} 来使用他们。
4.4、Settings 属性
- settings.localRepository:自定义本地库路径,默认在 ${user.home}/.m2 中
- settings.interactiveMode:交互模式,Maven 是否应该尝试与用户输入交互,默认是 true,如果不是 false。
- settings.offline:是否每次编译都去查找远程中心库, 如果此构建系统应以离线模式运行,则为 true,默认为
false。由于网络设置或安全原因,此元素对于构建无法连接到远程存储库的服务器非常有用。 - settings.pluginGroups:插件组,例如 org.mortbay.jetty
4.5、Java系统属性
- java.version:Java 运行时环境版本
- java.vendor:Java 运行时环境供应商
- java.vendor.url:Java 供应商的 URL
- java.home:Java 安装目录
- java.vm.specification.version:Java 虚拟机规范版本
- java.vm.specification.vendor:ava 虚拟机规范供应商
- java.vm.specification.name:Java 虚拟机规范名称
- java.vm.version:Java 虚拟机实现版本
- java.vm.vendor:Java 虚拟机实现供应商
- java.vm.name:Java 虚拟机实现名称
- java.class.path:Java 类路径
- os.name:操作系统的名称
- file.separator:文件分隔符(在 UNIX 系统中是“/”)
- user.name:用户的账户名称
- user.home:用户的主目录
- user.dir:用户的当前工作目录
4.6、环境变量属性
所有环境变量都可以使用以 env. 开头的 Maven 属性引用。比如:${env.JAVA_HOME} 表示环境变量的值。
5、构建设置
build 标签可以是单独的,也可以是包含在 profile 标签里面,如下所示:
<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">
<!– "Project Build" contains more elements than just the BaseBuild set –>
<build>…</build>
<profiles>
<profile>
<!– "Profile Build" contains a subset of "Project Build"s elements –>
<build>…</build>
</profile>
</profiles>
</project>
build 标签包含两个子标签,分别是 Resources 标签和 Plugins 标签,下面分别介绍下这两个标签。
5.1、Resources 标签
<resources>
<resource>
<targetPath>META-INF/plexus</targetPath>
<filtering>false</filtering>
<directory>${basedir}/src/main/plexus</directory>
<includes>
<include>configuration.xml</include>
</includes>
<excludes>
<exclude>**/*.properties</exclude>
</excludes>
</resource>
</resources>
- targetPath:资源的打包路径,该路径相对 target/classes 目录。
- filtering:主要用来替换项目中的资源文件(* .xml、* . properties)当中的 $ {…} 属性值如 $ {db.url}
如果 filtering=true 在 resources 目录中存在资源文件并且配置了 db.url=aaa 的话,
在项目编译的时候,就会自动的把 pom 文件中的 ${db.url} 替换为 aaa。 - directory:描述存放资源的目录,该路径相对 pom 的路径。
- includes:包含的模式列表,例如 **/*.xml。
- excludes:排除的模式列表,例如 **/*.xml。
5.2、Plugins 标签
在子项目中引入插件,同样,子项目继承父项目的 plugin 设置,并可以自由定义。
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-source-plugin</artifactId>
</plugin>
</plugins>
如果用树形图来表达 pom.xml,那么会更加清晰:
mavenTest
|—— Lifecycle
|—— Plugins
|—— Dependencies
可见,除了项目的基本信息(Maven 坐标、打包方式等)以外,每个 pom.xml 都应该包括:
- Lifecycle(生命周期)
- Plugins(插件)
- Dependencies(依赖)
Lifecycle 是项目构建的生命周期,它包括 9 个 Phase(阶段)。
大家知道,Maven 是一个核心加上多个插件的架构,而这些插件提供了一系列非常重要的功能,这些插件会在许多阶段里发挥重要作用。
阶段 | 插件 | 作用 |
---|---|---|
clean | clean | 清理自动生成的文件,也就是 target 目录 |
validate | 由 Maven 核心负责 | 验证 Maven 描述文件是否有效 |
compile | compiler、resources | 编译 Java 源码 |
test | compiler、surefire、resources | 运行测试代码 |
package | war | 项目打包,就是生成构件包,也就是打 war 包 |
verify | 由 Maven 核心负责 | 验证构件包是否有效 |
install | install | 将构件包安装到本地仓库 |
site | site | 生成项目站点,就是一堆静态网页文件,包括 JavaDoc |
deploy | deploy | 将构件包部署到远程仓库 |
以上表格中所出现的插件名称实际上是插件的别名,比如:compiler 实际上是 org.apache.maven.plugins:maven-compiler-plugin:2.3.2,这个才是 Maven 插件的完全名称。
每个插件又包括了一些列的 Goal(目标),以 compiler 插件为例,它包括以下目标:
- compiler:help:用于显示 compiler 插件的使用帮助。
- compiler:compile:用于编译 main 目录下的 Java 代码。
- compiler:testCompile:用于编译 test 目录下的 Java 代码。
可见,插件目标才是具体干活的人,一个插件包括了一个多个目标,一个阶段可由零个或多个插件来提供支持。
我们可以在 pom.xml 中定义一些列的项目依赖(构件包),每个构件包都会有一个 Scope(作用域),它表示该构件包在什么时候起作用,包括以下五种:
- compile:默认作用域,在编译、测试、运行时有效
- test:对于测试时有效
- runtime:对于测试、运行时有效
- provided:对于编译、测试时有效,但在运行时无效
- system:与 provided 类似,但依赖于系统资源
四、使用 Maven 命令
例如:mvn archetype:generate,mvn tomcat7:run-war 等。其实,可使用两种不同的方式来执行 Maven 命令:
- 方式一:mvn <插件>:< 目标 > [参数]
- 方式二:mvn <阶段>
现在我们接触到的都是第一种方式,而第二种方式才是我们日常中使用最频繁的,例如:
- mvn clean:清空输出目录(即 target 目录)
- mvn compile:编译源代码
- mvn package:生成构件包(一般为 jar 包或 war 包)
- mvn install:将构件包安装到本地仓库
- mvn deploy:将构件包部署到远程仓库
执行 Maven 命令需要注意的是:必须在 Maven 项目的根目录处执行,也就是当前目录下一定存在一个名为 pom.xml 的文件。
五、了解 settings.xml
<?xml version="1.0" encoding="UTF-8" ?>
<settings xmlns="http://maven.apache.org/SETTINGS/1.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/SETTINGS/1.0.0 http://maven.apache.org/xsd/settings-1.0.0.xsd">
<!-- 该值表示构建系统本地仓库的路径 -->
<localRepository>D:\repo</localRepository>
<!-- 根据环境参数来调整构建配置的列表 -->
<proxies>
<proxy>
<!--代理的唯一定义符,用来区分不同的代理元素。 -->
<id>optional</id>
<!--该代理是否是激活的那个。true则激活代理。当我们声明了一组代理,而某个时候只需要激活一个代理的时候,该元素就可以派上用处。 -->
<active>false</active>
<!--代理的协议。 协议://主机名:端口,分隔成离散的元素以方便配置。 -->
<protocol>http</protocol>
<!--代理的用户名,用户名和密码表示代理服务器认证的登录名和密码。 -->
<userName></userName>
<!--代理的密码,用户名和密码表示代理服务器认证的登录名和密码。 -->
<password></password>
<!--代理的主机名。协议://主机名:端口,分隔成离散的元素以方便配置。 -->
<host></host>
<!--代理的端口。协议://主机名:端口,分隔成离散的元素以方便配置。 -->
<port></port>
<!--不该被代理的主机名列表。该列表的分隔符由代理服务器指定;例子中使用了竖线分隔符,使用逗号分隔也很常见。 -->
<nonProxyHosts></nonProxyHosts>
</proxy>
</proxies>
<!-- 一般仓库的下载和部署是在pom.xml文件中的repositories和distributionManagement元素中定义的。
然而,一般类似用户名、密码(有些仓库访问是需要安全认证的)等信息不应该在pom.xml文件中配置,这些信息可以配置在 settings.xml 中。 -->
<servers>
<!-- 新版 -->
<server>
<!--这是server的id(注意不是用户登陆的id),该id与distributionManagement中repository元素的id相匹配。 -->
<id></id>
<!--鉴权用户名。鉴权用户名和鉴权密码表示服务器认证所需要的登录名和密码。 -->
<username></username>
<!--鉴权密码 。鉴权用户名和鉴权密码表示服务器认证所需要的登录名和密码。密码加密功能已被添加到2.1.0 +。详情请访问密码加密页面 -->
<password></password>
</server>
<server>
<!--这是server的id(注意不是用户登陆的id),该id与distributionManagement中repository元素的id相匹配。 -->
<id></id>
<!--鉴权用户名。鉴权用户名和鉴权密码表示服务器认证所需要的登录名和密码。 -->
<username></username>
<!--鉴权密码 。鉴权用户名和鉴权密码表示服务器认证所需要的登录名和密码。密码加密功能已被添加到2.1.0 +。详情请访问密码加密页面 -->
<password></password>
</server>
</servers>
<!-- 为仓库列表配置的下载镜像列表 -->
<mirrors>
<mirror>
<!-- 镜像的唯一标识 -->
<id>nexus-aliyun</id>
<!-- 指定镜像规则,什么情况下从镜像仓库拉取。其中, *: 匹配所有,所有内容都从镜像拉取 -->
<mirrorOf>*</mirrorOf>
<!-- 名称描述 -->
<name>Nexus aliyun</name>
<!-- 地址 -->
<url>http://maven.aliyun.com/nexus/content/groups/public</url>
</mirror>
</mirrors>
<profiles>
<profile>
<!-- profile的唯一标识 -->
<id>dev</id>
<!-- 远程仓库列表 -->
<repositories>
<repository>
<!--远程仓库唯一标识 -->
<id>jcf-rep</id>
<!--远程仓库URL -->
<url></url>
<!--如何处理远程仓库里发布版本的下载 -->
<releases>
<!--true或者false表示该仓库是否为下载某种类型构件(发布版,快照版)开启。 -->
<enabled>true</enabled>
</releases>
<!--如何处理远程仓库里快照版本的下载 -->
<snapshots>
<!--true或者false表示该仓库是否为下载某种类型构件(发布版,快照版)开启。 -->
<enabled>true</enabled>
</snapshots>
</repository>
</repositories>
<!-- 插件的远程仓库列表 -->
<pluginRepositories>
<pluginRepository>
<!--插件仓库唯一标识 -->
<id>jcf-rep</id>
<!--插件仓库URL -->
<url></url>
<releases>
<!--true或者false表示该仓库是否为下载某种类型构件(发布版,快照版)开启。 -->
<enabled>true</enabled>
</releases>
<snapshots>
<!--true或者false表示该仓库是否为下载某种类型构件(发布版,快照版)开启。 -->
<enabled>true</enabled>
</snapshots>
</pluginRepository>
</pluginRepositories>
</profile>
<profile>
<id>jdk-1.8</id>
<activation>
<activeByDefault>true</activeByDefault>
<jdk>1.8</jdk>
</activation>
<properties>
<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>
</profile>
</profiles>
<activeProfiles>
<!-- 要激活的profile id -->
<activeProfile>dev</activeProfile>
<activeProfile>jdk-1.8</activeProfile>
</activeProfiles>
</settings>