全面详细、通俗易懂的Maven

前言

Maven是一个构建管理、依赖管理的项目管理工具。构建是指使用源代码、图片、配置文件等各种源文件开发出可以用于生产的项目的过程。依赖是指项目之间关系,如果A项目里用到了B项目的资源,那么就说A项目依赖于B项目。依赖管理需要解决的问题如下:

  • jar包的下载:Maven在本地存储库中查找。每当项目引用本地存储库中不可用的依赖项时,Maven将从远程存储库将该依赖项下载到本地存储库中。
  • jar包之间的依赖关系:通过依赖之间的传递性自动完成。
  • jar包之间的冲突:通过对依赖的配置进行调整,让某些jar包不会被导入。

Maven的工作机制如下:

在这里插入图片描述

创建Maven项目

Maven项目可以手动创建可以以使用archetype插件创建:

mvn archetype:generate                                  

无论通过哪种方式创建,项目的结构必须符合以下约定:

my-app
|-- pom.xml
`-- src
    |-- main
    |   `-- java
    |       `-- com
    |           `-- mycompany
    |               `-- app
    |                   `-- App.java
    `-- test
        `-- java
            `-- com
                `-- mycompany
                    `-- app
                        `-- AppTest.java

如果项目需要静态文件,那么可以将它们放到resources文件夹下,编译后resources下的静态资源会放到类路径下:

my-app
|-- pom.xml
`-- src
    |-- main
    |   |-- java
    |   |   `-- com
    |   |       `-- mycompany
    |   |           `-- app
    |   |               `-- App.java
    |   `-- resources
    |       `-- application.properties
    |           
    `-- test
        `-- java
            `-- com
                `-- mycompany
                    `-- app
                        `-- AppTest.java

POM

POM:Project Object Model,项目对象模型,它将项目抽象为一个模型,再使用程序中的对象来描述这个模型,这样就实现使用程序来管理项目。POM具体体现在Maven项目根目下的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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
  
  <!--当前pom.xml采用的标签版本-->
  <modelVersion>4.0.0</modelVersion>
  <!--Maven坐标-->
  <groupId></groupId>
  <artifactId></artifactId>
  <version></version>
  <!--当前项目的打包方式-->
  <packaging></packaging>
  <!--依赖管理-->
  <dependencies></dependencies>
  <!--父项目-->
  <parent></parent>
  <!--依赖关系管理-->
  <dependencyManagement></dependencyManagement>
  <!--子项目-->
  <modules></modules>
  <!--属性-->
  <properties></properties>
  <!--构建设置-->
  <build></build>
  <reporting></reporting>

  <profiles></profiles>
</project>

Super POM

如果一个POM没有父POM,那么它就默认扩展自Super POM,Super POM进行了大量的默认配置。这些POM中的设置按照从下到上依次覆盖的顺序组成了最终起作用的有效POM。

在这里插入图片描述

坐标

Maven使用三个向量在仓库中唯一定位一个jar包,也决定了jar包在仓库中的存储路径:

<!--公司过组织的id,一般使用域名的倒序-->
<groupId></groupId>
<!--项目的名称-->
<artifactId></artifactId>
<!--项目版本号-->
<version></version>

属性

可以在POM中使用以下标签自定义属性也可以为已有属性赋值,通过${}表达式来访问这些属性值。

<properties></properties>

环境配置

项目处于不同的环境会有不同的配置,<profile>标签可以为不同的环境进行不同的配置,除了 <modelVersion>以及坐标标签外,几乎所有的其它标签都可以在<profile>标签中配置,如果没有配置<profile>标签,那么当前POM的配置会默认在一个<profiles>标签中。

<profiles>
    <profile>
        <!--唯一标识-->
        <id></id>
        <!--激活方式-->
        <activation>
            <!--是否默认激活-->
            <activeByDefault></activeByDefault>
            <!--指定jdk版本下激活-->
            <jdk></jdk>
        </activation>
        <!--配置-->
        <properties></properties>
    </profile>
</profiles>

<profile>标签的激活方式有很多,可以默认激活、基于环境信息激活以及指定激活等,一个<profiles>标签一旦被激活,那么它所定义的所有配置都会覆盖原来POM中对应层次的元素。

继承和聚合

如果有几个Maven项目,并且它们都有相似的配置,那么可以通过提取这些相似的配置并创建一个父项目来重构项目。如果我们可以改动父项目,那么就可以将新模块添加到父项目的根目录中:

my-app
|-- pom.xml
|-- my-module
|   `-- pom.xml

添加完成后在子项目的pom.xml中添加以下配置:

<parent>
  <groupId>com.mycompany.app</groupId>
  <artifactId>my-app</artifactId>
  <version>1</version>
</parent>

如果父项目已经安装在我们的本地存储库中,或者在某个特定的目录结构中,比如:

|-- my-module
|   `-- pom.xml
`-- parent
    `-- pom.xml

此时可以通过以下方式指定父项目的位置从而实现继承:

<parent>
  <groupId>com.mycompany.app</groupId>
  <artifactId>my-app</artifactId>
  <version>1</version>
  <relativePath>../parent/pom.xml</relativePath>
</parent>

如果有一组一起构建或处理的项目,可以创建一个父项目,并让那个父项目声明这些项目为它的模块。通过这样做,只需要构建父项目,其余的模块就会被自动构建。如果我们可以改动子项目,那么就可以将子模块添加到父项目的根目录中:

my-app
|-- pom.xml
|-- my-module
|   `-- pom.xml

添加完成后在父项目的pom.xml中添加以下配置:

<modules>
  <module>my-module</module>
</modules>

如果子项目已经安装在我们的本地存储库中,或者在某个特定的目录结构中,比如:

|-- my-module
|   `-- pom.xml
`-- parent
    `-- pom.xml

此时可以通过以下方式指定子项目的位置从而实现聚合:

<modules>
  <module>../my-module</module>
</modules>

可以让一些子项目指定一个父项目,同时让这个父项目将这些子项目指定它的模块。那么就可以同时具有继承和聚合的优点,此时夫项目的打包类型必须指定为pom。

插件

Maven核心程序负责Maven的总体调度,具体的功能由具体的插件完成。一个插件可以对应多个目标,每一个目标都和生命周期内的某一环节对应。运行差价目标的命令格式如下:

mvn <plugin>:<target> [options]

配置

通过在<build>标签下的<plugins>标签可以添加插件:

<plugins>
    <plugin>
    	<!--插件坐标-->
        <groupId></groupId>
        <artifactId></artifactId>
        <version></version>
        <executions>
        	<!--执行策略-->
            <execution>
            	<!--唯一标识-->
                <id></id>
                <!--关联的生命周期阶段-->
                <phase></phase>
                <!--关联指定生命周期的目标-->
                <goals></goals>
            </execution>
        </executions>
        <!--每个插件的配置各不相同-->
    </plugin>
</plugins>

插件关系管理

通过在<build>标签下的<pluginManagement>标签中集中配置插件信息,这样可以保证子项目的插件版本一致。

<pluginManagement>
    <plugins>
        <plugin></plugin>
    </plugins>
</pluginManagement>

自定义插件

  • 第一步:新建项目引入依赖并将打包方式改为maven-plugin,项目名称必须满足${prefix}-maven-pluginmaven-${prefix}-plugin的形式:
<groupId>com.chinesecooly</groupId>
<artifactId>maven-plugin</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>hello-maven-plugin</packaging>

<properties>
    <maven.compiler.source>8</maven.compiler.source>
    <maven.compiler.target>8</maven.compiler.target>
</properties>

<dependencies>
    <dependency>
        <groupId>org.apache.maven.plugin-tools</groupId>
        <artifactId>maven-plugin-annotations</artifactId>
        <version>3.5.2</version>
    </dependency>
    <dependency>
        <groupId>org.apache.maven</groupId>
        <artifactId>maven-plugin-api</artifactId>
        <version>3.6.3</version>
    </dependency>
</dependencies>
  • 第二步:创建mojo类,该类是每个Maven插件的核心类:
//指定插件名称
@org.apache.maven.plugins.annotations.Mojo(name="sayHello")
public class Mojo extends AbstractMojo {
    @Override
    public void execute() throws MojoExecutionException, MojoFailureException {
        //目标功能
        getLog().info("hello maven plugin");
    }
}
  • 第三步:将插件安装到本地仓库
  • 第四步:在新项目中配置使用插件:
<build>
    <plugins>
        <plugin>
            <groupId>com.chinesecooly</groupId>
            <artifactId>hello-maven-plugin</artifactId>
            <version>1.0-SNAPSHOT</version>
            <executions>
                <execution>
                    <id>hello-plugin</id>
                    <phase>validate</phase>
                    <goals>
                        <goal>sayHello</goal>
                    </goals>
                </execution>
            </executions>
        </plugin>
    </plugins>
</build>
  • 第五步:在bash运行插件:
mvn hello:sagHello

构建管理

使用Maven进行构建操作时,必须进入到项目的根目录。

构建插件及构建流程

构建过程的主要环节如下:

  • 清理:删除上一次构建的结果,为下一次构建做准备。
mvn clean
  • 编译:将java源文件编译成字节码文件。
mvn compile

编译后的项目放在以下目录:

my-app
|--target
	`--classes
		`-- com
	         `-- mycompany
	              `-- app
	                  `-- App.class
  • 测试:运行提前准备好的测试文件。
mvn test
  • 打包:将java项目打为jar包或将web项目打为war包。
mvn package

创建的jar包放在以下目录:

my-app
|--target
	`--classes
	`--my-app-1.0-SNAPSHOT.jar
  • 安装:将打包操作生成的jar包或者war包安装到本地仓库,并生成一个与项目同名的pom.xml文件。
mvn install

生命周期

为了实现构建过程的自动化,Mvaen设定了三个主要的生命周期,生命周期中每一个环节对应构建过程中的一个操作,当执行某一个环节时该环节前的所有环节都会自动执行。

生命周期作用环节
Clean清理操作pre-clear
clean
post-clean
Site生成项目信息站点pre-site
site
post-site
deploy-site
Default主要构建过程
process-resources:复制并处理资源文件,移至target目录下
compile:编译main目录下的源码

process-test-resources:复制并处理资源文件,移至测试target目录下
test-compile:编译test目录下的源码

test:运行测试代码

package:打包

install:安装

deploy:上传

构建设置

<build>标签可以修改默认的构建设置,在该标签中可以定义诸如项目结构等大量的配置:

<!--主体源文件存放目录-->
<sourceDirectory></sourceDirectory>
<!--脚本源文件存放目录-->
<scriptSourceDirectory></scriptSourceDirectory>
<!--测试源文件存放目录-->
<testSourceDirectory></testSourceDirectory>
<!--主体字节码文件存放目录-->
<outputDirectory></outputDirectory>
<!--测试字节码文件存放目录-->
<testOutputDirectory></testOutputDirectory>
<!--主体资源文件存放目录-->
<resources></resources>
<!--测试资源文件存放目录-->
<testResources></testResources>
<!--构建结果输出目录-->
<directory></directory>

<resources>标签和<testResources>标签还可以进行一些资源过滤的操作:

<resources>
    <resource>
    	<!--资源文件存放目录-->
        <directory></directory>
        <!--是否开启资源过滤功能-->
        <filtering></filtering>
        <!--排除文件-->
        <excludes></excludes>
        <!--包含文件-->
        <includes></includes>
        <!--目标存放目录-->
        <targetPath></targetPath>
    </resource>
</resources>

依赖管理

依赖的范围

依赖的范围是指依赖在空间和时间上的作用域。

<scope></scope>
范围值main目录(空间)test目录(空间)开发过程(时间)部署到服务器(时间)说明
compile默认范围
provided×只有当jdk或容器已提供该依赖之后才使用该值。
runtime×开发时不需要,运行时需要
test××用于测试目的的依赖使用该值
system×system范围依赖与provide类似,但是必须显示的提供一个对于本地系统中jar文件的路径。一般不推荐使用。
import----该值只能用于<dependencyManagement>标签中的依赖。并且依赖的打包类型必须是pom,它的作用是将依赖的<dependencyManagement>标签l中的依赖列表加入到当前工程

依赖的传递性

当依赖的范围值是compile时,项目自身依赖的依赖都会传递到当前项目。

 A
  ├── B
  │   └── C
  │       └── D-2.0
  └── E
      └── D-1.0

当遇到多个版本作为依赖关系时,Maven会使用依赖项树中与您的项目最接近的依赖项的版本。在上面的依赖树中,D-1.0将在构建A时使用。我们也可以可以通过在项目的POM中显式声明它来保证某个版本。如果两个依赖项版本在依赖项树中的深度相同,则第一个声明获胜。

可选依赖

如果有些依赖只是支持当前项目的某些特性,可以将此依赖标记为可选,这样在其它项目依赖当前项目时这些可选依赖将不会传递。比如在E中将D标记为可选依赖,那么D将不会传递到A。

<optional>true</optional>

依赖排除

依赖排除用于阻断依赖的传递。

<exclusions>
  <exclusion>
    <groupId></groupId><artifactId></artifactId>
  </exclusion>
</exclusions>

依赖关系管理

依赖关系管理是一种集中依赖项信息的机制。当有一组从公共父项目继承的项目时,可以将有关依赖的所有信息放在父POM中,并在子POM中对依赖进行更简单的引用。

<dependencyManagement>
  <dependencies>
    <dependency>
      <groupId></groupId>
      <artifactId></artifactId>
      <version></version>
    </dependency>
  </dependencies>
</dependencyManagement>

依赖冲突

当一个项目存在同一个依赖不同版本或不同依赖包含同名类的问题时,就产生了依赖冲突。当出现这种问题时可以使用enforcer插件进行检测,首先添加插件:

<build>
    <plugins>
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-enforcer-plugin</artifactId>
            <version>3.0.0</version>
            <executions>
                <execution>
                    <id>enforce-dependencies</id>
                    <phase>validate</phase>
                    <goals>
                        <goal>display-info</goal>
                        <goal>enforce</goal>
                    </goals>
                </execution>
            </executions>
            <dependencies>
                <dependency>
                    <groupId>org.codehaus.mojo</groupId>
                    <artifactId>extra-enforcer-rules</artifactId>
                    <version>1.5.1</version>
                </dependency>
            </dependencies>
            <configuration>
                <rules>
                    <banDuplicateClasses>
                        <findAllDuplicates>true</findAllDuplicates>
                    </banDuplicateClasses>
                </rules>
            </configuration>
        </plugin>
    </plugins>
</build>

然后执行以下命令:

mvn enforcer:enforcer

执行完成后控制台就会打印产生冲突的依赖和类,然后通过依赖排除等方式解决依赖冲突问题。

引入体系外依赖

如果想要引入一个体系外部的依赖可以通过以下方式:

  • 首先将外部依赖强行安装到本地仓库:
mvn install:install-file \
-Dfile=<外部依赖路径> \
-DartifactId=<项目的名称> \
-Dversion=<版本号> \
-Dpackaging=<打包方式>

仓库

仓库用于存储依赖,它分为本地仓库和远程仓库,远程仓库又分为私服仓库和中央仓库仓库。本地仓库位于当前电脑,只为本机的Maven项目服务,通过以下标签设置本地仓库的位置:

<localRepository></localRepository>

私服仓库位于局域网内的某台服务器上,它为同在一个局域网内的Maven项目服务,可以使用Nexus搭建一个私服仓库。中央仓库位于互联网中的服务器上,为所有Maven项目服务,通过以下标签设置远程仓库的位置:

<mirrors>
  <mirror>
    <id>nexus-aliyun</id>
    <mirrorOf>central</mirrorOf>
    <name>Nexus aliyunn</name>
    <url>http://maven.aliyun.com/nexus/content/groups/public/</url>
  </mirror>
</mirrors>
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

亻乍屯页女子白勺

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值