Maven教程

此教程的目标是介绍Maven的基本知识及常见操作。

0. 前言

在没有Maven之前,当我们开发一个Java项目的时候,项目目录结构没有一个统一的标准规范,很多时候配置文件、测试文件、前端页面放哪里都是根据开发人员自己的喜好决定。

同时我们经常需要引用其他jar包,并下载下来放到项目中。然后点击编译的时候会出现ClassNotFoundException,找了半天可能发现,竟然还是少了某个jar包。

其实在Maven之前也是有类似的项目管理构建工具,比如make或Ant,但是使用那些构建工具配置繁琐,效率比较低。

为了解决以上问题,Van Zyl, Jason,也就是“Maven他爸”出现了,他给Java世界带来了一种全新的项目构建方式,给无数Java码农带来了福音。

他开发的Maven的主要解决了两个问题:

  1. 统一Java项目管理规范
  2. 统一管理jar包

所以,为了更加愉快地开发,并且让后面维护系统的人员也愉快。让我们开始愉快地使用Maven吧。

1. 安装使用

首先,我们可从Maven官网上面去下载Maven压缩包,解压后,配置环境变量:

  • MAVEN_HOME=D:softwareapache-maven-3.5.0-binapache-maven-3.5.0
  • MAVEN_OPTS=-Xms128m -Xmx512m

具体路径可改为自己本地路径,并配置不同大小MAVEN_OPTS可让Maven跑得快点。

然后打开cmd,输入mvn -v,出现Maven的版本信息提示,说明安装成功!

其次,我们需要修改一下Maven的配置文件:apache-maven-3.5.0confsettings.xml,新增一个本地目录作为本地仓库并修改localRepository路径。
同时,修改中央仓库地址,推荐使用阿里云镜像:

 <mirror>
    <id>nexus-aliyun</id>
    <mirrorOf>central</mirrorOf>
    <name>Nexus aliyun</name>
    <url>http://maven.aliyun.com/nexus/content/groups/public</url>
</mirror>
 <!-- 阿里云仓库 -->
  <mirror>
       <id>alimaven</id>
       <mirrorOf>central</mirrorOf>
       <name>aliyun maven</name>
        <url>http://maven.aliyun.com/nexus/content/repositories/central/</url>
     </mirror>

   <!-- 中央仓库1 -->
    <mirror>
        <id>repo1</id>
        <mirrorOf>central</mirrorOf>
        <name>Human Readable Name for this Mirror.</name>
        <url>http://repo1.maven.org/maven2/</url>
     </mirror>
    <!-- 中央仓库2 -->
    <mirror>
       <id>repo2</id>
       <mirrorOf>central</mirrorOf>
        <name>Human Readable Name for this Mirror.</name>
       <url>http://repo2.maven.org/maven2/</url>
    </mirror>

Maven寻找jar包首先会从本地仓库中去找,如果没有,再到私服(如果有配置公司私服仓库的话)去找,最后再到中央仓库中去寻找。

2. 基本概念

接着,我们需要了解一些Maven的基本概念。

2.1 Maven项目的生命周期

Maven把一个项目的构建分为不同的生命周期,这个过程通常包括:

  • 验证(validate): 验证项目正确和所有必要信息是可用的。
  • 编译(complile): 编译项目源码。
  • 测试(test): 使用合适的单元测试框架测试编译后的代码。这些测试代码不需要被打包或者发布。
  • 打包(package): 将编译后的代码打包成指定的格式,比如jar包或者war包。
  • 校验(verify): 对集成测试结果进行任意检查,以确保满足质量标准。
  • 安装(install): 将打成的jar包安装到本地仓库,以便其他本地项目依赖使用。
  • 发布(deploy): 在构建环境中完成,将最终包复制到远程存储库以与其他开发人员和项目共享。

2.2 Maven的标准工程结构

-项目目录
-pom.xml 用于maven的配置文件
	-src 源代码目录
		-src/main 工程源代码目录
			-src/main/java 工程java源代码目录
		-src/main/resource 工程的资源目录
		-src/test 单元测试目录
			-src/test/java
	-target 输出目录,所有的输出物都存放在这个目录下
		-target/classes 编译之后的class文件

这个目录结构并不是不可更改的,但是Maven的理念是“约定大于配置”,这些配置是默认的,除非必要,并不需要去修改那些约定内容。采用"约定优于配置"的策略可以减少修改配置的工作量,也可以降低学习成本,更重要的是,给项目引入了统一的规范。

2.3 Maven的版本规范

Maven使用以下几个元素来唯一定位某一个输出物: groupId: artifactId: packaging: version。

  • groupId: 团体、组织的标识符。团体标识的约定是,它以创建这个项目的组织名称的逆向域名(reverse domain name)开头。一般对应着JAVA的包的结构。例如org.apache
  • artifactId: 单独项目的唯一标识符。比如我们的tomcat, commons等。不要在artifactId中包含点号(.)。
  • version: 一个项目的特定版本。
  • packaging: 项目的类型,默认是jar,描述了项目打包后的输出。类型为jar的项目产生一个JAR文件,类型为war的项目产生一个web应用。
  • SNAPSHOT: 这个版本一般用于开发过程中,表示不稳定的版本。
  • LATEST: 指某个特定构件的最新发布,这个发布可能是一个发布版,也可能是一个snapshot版,具体看哪个时间最后。
  • RELEASE: 指最后一个发布版。

3. 创建Maven项目

创建Maven项目的方法有许多种,最基本的可以使用mvn archetype:generate命令行来创建,但通常我们都直接使用IDE来帮我们生成。下面就简单介绍一下使用IntelliJ IDEA来创建。

3.1 使用IDEA创建Maven项目

File -> New -> Project.. 选择合适的模板
Maven0
输入项目的基本信息,groupId是项目组织唯一的标识符,实际对应JAVA的包的结构,是main目录里java的目录结构。
artifactId就是项目的唯一的标识符,实际对应项目的名称,就是项目根目录的名称。
再选择本地Maven目录和配置文件,
Maven1
最后点击Finish,就会自动创建一个Maven工程。
Maven2

3.2 理解pom.xml

pom.xml 称为 Project Object Model(项目对象模型),它用于描述整个 Maven 项目,所以也称为 Maven 描述文件。当执行一个任务或目标时,Maven通过读取POM的配置信息来执行。同时,一个项目可以使用一个父pom来管理多个子模块,每个模块又单独拥有一个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/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>
 
  <!-- The Basics -->
  <groupId>...</groupId>
  <artifactId>...</artifactId>
  <version>...</version>
  <packaging>...</packaging>
  <dependencies>...</dependencies>
  <parent>...</parent>
  <dependencyManagement>...</dependencyManagement>
  <modules>...</modules>
  <properties>...</properties>
 
  <!-- Build Settings -->
  <build>...</build>
  <reporting>...</reporting>
 
  <!-- More Project Information -->
  <name>...</name>
  <description>...</description>
  <url>...</url>
  <inceptionYear>...</inceptionYear>
  <licenses>...</licenses>
  <organization>...</organization>
  <developers>...</developers>
  <contributors>...</contributors>
 
  <!-- Environment Settings -->
  <issueManagement>...</issueManagement>
  <ciManagement>...</ciManagement>
  <mailingLists>...</mailingLists>
  <scm>...</scm>
  <prerequisites>...</prerequisites>
  <repositories>...</repositories>
  <pluginRepositories>...</pluginRepositories>
  <distributionManagement>...</distributionManagement>
  <profiles>...</profiles>
</project>

Maven3
由上图可以看出,除了项目的基本信息(Maven 坐标、打包方式等)以外,每个 pom.xml 都还包括:

  • Lifecycle(生命周期)

  • Plugins(插件)

  • Dependencies(依赖)

每个插件又包括了一些多个 Goal(目标),以 compiler 插件为例,它包括以下目标:

  • **compiler:

  • **:用于显示 compiler 插件的使用帮助。

  • compiler:compile:用于编译 main 目录下的 Java 代码。

  • compiler:testCompile:用于编译 test 目录下的 Java 代码。

另外,pom.xml中定义的依赖包,其中有个Scope(作用域),它表示该依赖包在什么时期起作用,分别有下列几种情况:

  • compile:默认作用域,在编译、测试、运行时有效

  • test:对于测试时有效

  • runtime:对于测试、运行时有效

  • provided:对于编译、测试时有效,但在运行时无效

  • system:与 provided 类似,但依赖于系统资源

Maven4

3.2.1 常用标签

pom使用XML描述,常见的一些标签功能说明如下:

  • modelVersion:这个是 POM 的版本号,现在都是 4.0.0 的,必须得有,但不需要修改。
  • groupId、artifactId、version:分别表示 Maven 项目的组织名、构件名、版本号,它们三个合起来就是 Maven 坐标,根据这个坐标可以在 Maven 仓库中对应唯一的 Maven 构件。
  • packaging:表示该项目的打包方式,war 表示打包为 war 文件,默认为 jar,表示打包为 jar 文件。
  • name、url:表示该项目的名称与 URL 地址,意义不大,可以省略。
  • build: 表示与构建相关的配置。
  • parent: maven 支持继承功能。子 POM 可以使用 parent 指定父 POM ,然后继承其配置。
  • dependencyManagement: 在项目的 parent 层,可以通过 dependencyManagement 元素来管理 jar 包的版本,让子项目中引用一个依赖而不用显示的列出版本号.
  • dependencies: 定义该项目的依赖关系,其中每一个 dependency 对应一个 Maven 项目,可见 Maven 坐标再次出现,还多了一个 scope,表示作用域。相对于 dependencyManagement,所有声明在父项目中 dependencies 里的依赖都会被子项目自动引入,并默认被所有的子项目继承。
  • properties: 属性列表。定义的属性可以在 pom.xml 文件中任意处使用。使用方式为 ${propertie} 。
  • repositories: 远程仓库列表,用来获取本地需要的依赖包和扩展。
  • pluginRepositories: 远程插件仓库列表,用来获取本地需要的插件。
  • modules: 模块列表,创建多模块项目中使用。
  • profiles: 用于在不同的环境下应用不同的配置。一套配置即称为一个Profile。比如开发、测试、生产不同环境需要不同配置,再根据激活条件激活某个profile。
  • optional: 让其他项目知道,当使用此项目时,不需要这种依赖性才能正常工作。
  • exclusions:包含一个或多个排除元素,每个排除元素都包含一个表示要排除的依赖关系的 groupId 和 artifactId。与可选项不同,可能或可能不会安装和使用,排除主动从依赖关系树中删除自己。
  • resources: 资源元素的列表,每个资源元素描述与此项目关联的文件和何处包含文件。
  • targetPath: 指定从构建中放置资源集的目录结构。目标路径默认为基本目录。将要包装在 jar 中的资源的通常指定的目标路径是META-INF。
  • filtering: 值为 true 或 false。表示是否要为此资源启用过滤。
  • directory: 值定义了资源的路径。构建的默认目录是${basedir}/src/main/resources
  • includes: 一组文件匹配模式,指定目录中要包括的文件,使用*作为通配符。
  • excludes: 与 includes 类似,指定目录中要排除的文件,使用*作为通配符。
3.2.2 常用插件

Maven中使用插件只需要在pom.xml文件中添加plugin就行:

<build>
    <plugins>
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-compiler-plugin</artifactId>
            <configuration>
                <source>${java.version}</source>
                <target>${java.version}</target>
                <encoding>${project.build.sourceEncoding}</encoding>
            </configuration>
        </plugin>
    </plugins>
</build>

常用的一些插件如下:

插件名 描述
maven-resources-plugin 文件资源配置
maven-compiler-plugin 编译源代码
maven-surefire-plugin 单元测试使用
maven-surefire-plugin 单元测试使用
maven-jar-plugin 打jar包
maven-war-plugin 打war包
maven-assembly-plugin 打包含依赖包的完整包
maven-shade-plugin 打包含依赖的全包且可以配置主类
maven-source-plugin 含源码打包
maven-exec-plugin 执行命令
maven-javadoc-plugin 生成java文档
mybatis-generator-maven-plugin 生成mybatis映射
tomcat-maven-plugin 相当于使用内置tomcat启动、调试、运行项目
spring-boot-maven-plugin 将spring boot项目打成可执行的jar包
tomcat-maven-plugin 相当于使用内置tomcat启动、调试、运行项目
3.2.3 常用命令
生命周期 描述
mvn validate 验证项目是否正确,以及所有为了完整构建必要的信息是否可用
mvn generate-sources 生成所有需要包含在编译过程中的源代码
mvn generate-resources 生成所有需要包含在打包过程中的资源文件
mvn compile 编译项目的源代码
mvn test-compile 编译测试代码
mvn test 运行应用程序中的单元测试
mvn site 生成项目相关信息的网站
mvn package 将编译好的代码打包成可分发的格式,如JAR,WAR
mvn install 安装包至本地仓库,以备本地的其它项目作为依赖使用
mvn clean 清除目标目录中的生成结果
mvn clean compile 将.java类编译为.class文件
mvn clean package 先清除目标目录中的生成结果,再进行打包
mvn dependency:list 查看已解析依赖
mvn dependency:tree 查看依赖树
mvn help:active-profiles 查看当前激活的profiles
mvn -Dmaven.test.skip=true 忽略测试文档编译
3.2.4 常见问题
3.2.4.1 查找最新版本jar包

可以在http://mvnrepository.com/站点搜寻你想要的jar包版本。例如,想要使用log4j,可以找到需要的版本号,然后拷贝对应的maven标签信息,将其添加到pom .xml文件中。
Maven5

3.2.4.2 IDEA 修改 JDK 版本后编译报错
  • 错误现象

修改 JDK 版本,指定 maven-compiler-plugin 的 source 和 target 为 1.8 。
然后,在 Intellij IDEA 中执行 maven 指令,报错:

[ERROR] Failed to execute goal org.apache.maven.plugins:maven-compiler-plugin:3.0:compile (default-compile) on project apollo-common: Fatal error compiling: 无效的目标版本: 1.8 -> [Help 1]
  • 错误原因

maven 的 JDK 源与指定的 JDK 编译版本不符。

  • 解决方案

IDEA查看项目的 Project Settings中的Project SDK是否正确,
Maven6
SDK 路径是否正确
Maven7
查看 Settings > Maven 的配置
Maven8
JDK for importer 是否正确
Maven9
Runner 是否正确。

3.2.4.3 重复依赖引用
  • 错误现象

有时候我们引用的依赖包还会再引用不同的一些第三方包,如果我们本地也引用了那些包或者其他依赖包中也引用了,并且版本不同,这时候就会出现jar包冲突。主要有两种情况:第一类是依赖了同一个jar包的多个版本。第二类是同样的类出现在了依赖的两个及以上的不同Jar包中。
经常会出现一些ClassNotFoundException,NoSuchMethodError,NoClassDefFoundError等异常。

  • 错误原因

同一个类出现在不同jar包,不同jar包的类有差异,加载的类不是我们程序期望的版本。

  • 解决方案

    1. 如果有异常堆栈信息,根据错误信息即可定位导致冲突的类名
    2. 若步骤1无法定位冲突的类来自哪个Jar包,可在应用程序启动时加上JVM参数-verbose:class或者-XX:+TraceClassLoading,日志里会打印出每个类的加载信息,如来自哪个Jar包
    3. 定位了冲突类的Jar包之后,通过mvn dependency:tree -Dverbose -Dincludes=:查看是哪些地方引入的Jar包的这个版本
    4. 确定Jar包来源之后,如果是第一类Jar包冲突,则可用排除不需要的Jar包版本或者在依赖管理中申明版本;若是第二类Jar包冲突,如果可排除,则用排掉不需要的那个Jar包,若不能排,则需考虑Jar包的升级或换个别的Jar包。
3.2.4.4 Profile使用
<profiles>
    <profile>
        <!-- 本地开发环境 -->
        <id>dev</id>
        <properties>
            <profiles.active>dev</profiles.active>
        </properties>
        <activation>
            <!-- 设置默认激活这个配置 -->
            <activeByDefault>true</activeByDefault>
        </activation>
    </profile>
    <profile>
        <!-- 发布环境 -->
        <id>release</id>
        <properties>
            <profiles.active>release</profiles.active>
        </properties>
    </profile>
    <profile>
        <!-- 测试环境 -->
        <id>beta</id>
        <properties>
            <profiles.active>beta</profiles.active>
        </properties>
    </profile>
</profiles> 

义了三个环境,分别是dev(开发环境)、beta(测试环境)、release(发布环境),其中开发环境是默认激活的(activeByDefault为true)。

Maven10

读取配置文件的过程如下:

1. 通过profile选中你要使用的环境
2. 通过package命令,将环境变量注入到application.properties中
3. 项目中加载application.xml文件

另外,profile根据不同需要可定义在不同位置,

1. 针对于特定项目的profile配置我们可以定义在该项目的pom.xml中。
2. 针对于特定用户的profile配置,我们可以在用户的settings.xml文件中定义profile。该文件在用户家目录下的“.m2”目录下。
3. 全局的profile配置。全局的profile是定义在Maven安装目录下的“conf/settings.xml”文件中的。

其中激活方式有几种:

1. 在pom.xml中设置<activeByDefault>true</activeByDefault> 
2. 打包时使用-P参数显示激活一个profile,比如mvn package –Pdev激活开发环境
3. 根据环境来激活profile,比如不同的操作系统激活不同的profile,也可以根据jdk版本的不同激活不同的profileelper

我们可以使用mvn help:active-profiles命令来查看当前激活的profile。

4. 参考资料

原文地址:https://www.cnblogs.com/universal/p/10411697.html