前言

Maven是我们经常用到的一个项目管理工具,但是我们有没有真正的对它进入了解呢?我是没有,所以才写下这篇博客来记录,我所知道的Maven知识,有不足的地方欢迎指正。

认识Maven

认识Maven从发音开始 美[ˈmeɪvn],中文谐音:美温,查了翻译后才知道我一直叫错了。

在Maven官网中有一段关于他自己的介绍,下面只取一部分:

The result is a tool that can now be used for building and managing any Java-based project. We hope that we have created something that will make the day-to-day work of Java developers easier and generally help with the comprehension of any Java-based project.

Google翻译:

Maven是一个工具,现在可用于构建和管理任何基于Java的项目。
我们希望我们已经创建了一些东西,使Java开发人员的日常工作变得更加容易,并且通常有助于理解任何基于Java的项目。

Maven有以下主要特点:

  • 构建工程项目简单、快捷
  • 统一的依赖管理
  • 丰富的插件功能
  • 灵活的项目迁移

Maven的构建方式是使用:

POM(项目对象模型)来进行统一管理和构建,所以我们只需要阅读Maven的构建方式,那么你就会了解其他的Maven工程,那么以后对于我们来说是非常节省时间的。

如何使用?

下载Maven:

http://maven.apache.org/download.cgi

然后在设置到电脑环境中,如果你是纯小白的话,建议在网上搜索Maven的安装教程,和JAVA很像,教程也很多。 点击直通车直接百度

配置好后,打开命令窗口,输入mvn --version 就可以看到当前的版本和其他信息了。

在这里插入图片描述

POM

pom是在Maven中是以pom.xml文件形式展现的。下面是最常用的Pom标签:

  <groupId>...</groupId>
  <artifactId>...</artifactId>
  <version>...</version>
  • groupId :一般用公司域名如: cn.wenhaha
  • artifactId : 功能名
  • version: 版本
  <packaging>...</packaging>

packaging表示打包方式,默认为jar,除此之外还有:pommaven-pluginejbwarearrar

  <dependencyManagement>...</dependencyManagement>
  <dependencies>...</dependencies>
  <dependency>...</dependency>

dependencyManagement

是一个依赖管理器,往往在整个项目中,只有父项目才能声明,当然这只是一种约束,你也可以在每个项目中,声明他。不过我不建议你这么做。 他的作用是:声明子项目需要用到的依赖包,但子项目中,不声明使用,也不会依赖某个包。这么说太抽象了,还是举个栗子。

父项目:pom.xml

<dependencyManagement>
  <dependencies>
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>fastjson</artifactId>
            <version>1.2.37</version>
        </dependency>
  </dependencies>
</dependencyManagement>

子项目:poim.xml


  <dependencies>
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>fastjson</artifactId>
        </dependency>
  </dependencies>

从上面的栗子中可以看出使用dependencyManagement的好处有:

  1. 统一管理版本号
  2. 事先声明,子项目需要在引用,这样可以避免其他不需要的子项目也依赖。

dependencies

这个就没啥可说的,上面栗子也看到了,这是一个依赖声明,项目中所需要的依赖包,都要在它里面声明,才可以哦。

说到依赖,有个查看项目依赖命令建议大家能够记下来,这是经常在项目中使用的:mvn dependency:tree

dependency

dependencies标签下,一般用于声明需要依赖哪些模块,不至于jar包。

<dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>4.12</version>
      <type>jar</type>
      <scope>test</scope>
      <optional>true</optional>
</dependency>

可以看出dependency标签下有很多子标签,前面的3个,已经在上面说了,下面我们从type开始慢慢说明。

  • Type
    type表示的是依赖的类型,默认为jar,除此之外还有ejb-clienttest-jar,当然不止于此,你也可以自定义一个type哦。

  • scope
    scope表示什么时候将这个依赖包加入到classPath中去,换句话说,什么时候才让依赖包生效。其中有5个可选项,默认为: compile

    1. compile : 编译,这些依赖项将传播到依赖项目。
    2. provided: 也是编译时,但不同的是,在运行时,才编译,而且不具备传递性。
    3. runtime: 运行时,表示编译不需要依赖项,但是用于执行。它位于运行时和测试类路径中,但不是编译类路径。
    4. test: 测试的时候才使用,正常运行时不需要使用到,而且不具备传递性。
    5. system : 使用本地jar包,来依赖项目,不会在项目仓库中查找。所以要通过systemPath来指定要依赖的文件。
  • optional
    默认为false,表示为项目直接是否依赖传递,如果为true就带表不依赖,反之依赖,什么意思呢?
    比如 A 项目 要依赖 B项目, 但是B项目是依赖C项目的,所以A依赖B时,也同时会依赖C,这时如果在B的optional属性为true那么A只会依赖B,不会把D也一起依赖进来。

传递性依赖

竟然说到依赖性关系,那么久要说下Maven的依赖机制了。为什么要有传递性依赖呢?传递性依赖不仅可以控制依赖和三种classpath的关系,还可以对传递性依赖产生影响。

这一章节和Scope下的5个属性相关,如果你直接跳到这里,可以往上面滑动一点点,就在上面的那一小节,可以回顾下,这5个属性的说明。

假设有3个项目,分别为A、B、C,他们直接的依赖关系如下图

依赖
依赖
A
B
C

那么 A和B是直接依赖关系,A和C是传递性依赖。

直接依赖
传递性依赖
A
B
C

问题是A为什么会传递性依赖于C,当A的状态发展改变时,又是如何依赖的?之前说到有一个标签为:scope那么就是通过这个标签来实现传递性依赖的。

下面的表格中,左边的一列是第一依赖,上面一行为第二依赖。 第一依赖是指 a->b为第一依赖,b->c是第二依赖,那么a->是传递依赖。

第一依赖
传递性依赖
第二依赖
A
B
C
compiletestprovidedruntime
compilecompile(*)--runtime
testtest--test
providedprovided-providedprovided
runtimeruntime--runtime

表格说明

  • 当第二依赖的范围为compile时,不会改变第一依赖。始终被依赖。
  • 当第二依赖的范围为test时,不会被传递性依赖。
  • 当第二依赖的范围为provided,只有第一依赖为provided,才会被传递。
  • 当第二依赖的范围为runtime,只有第一依赖为compile,传递依赖为runtime,其他不变。

排除依赖

还是上一个例子,A依赖B,B依赖C,那么A会依赖C,现在A不想依赖C,那么只需要把C给排除掉就可以了。

<dependency>
  <groupId>com.demo</groupId>
  <artifactId>project-b</artifactId>
  <version>1.0</version>
  <exclusions>
    <exclusion>
      <groupId>com.demo</groupId>
      <artifactId>project-c</artifactId>
    </exclusion>
  </exclusions>
</dependency>

依赖仲裁

假设有这么一种情况,A依赖B和C,B依赖了C,那么MAVEN到底是使用谁的C包呢?

依赖
依赖
依赖
A
B
C
C

第一原则:最短路径优先原则

从上图所示,A到C的路径是最短的,所以MAVEN会选择依赖于A中的C包


如果在加个D包,使得路径相等会怎么样呢?

依赖
依赖
依赖
依赖
A
B
C
D
D

第二原则:第一声明优先原则

根据上图所示,A是先声明B的,随后在声明C,所以,A是会依赖于B的D包,不会依赖于C的D包。

生命周期

Maven的生命周期是构建在插件的形式展现的,生命周期其实是算一个概念,在某个阶段运行什么。

Maven分为三个阶段的生命周期:cleandefaultsite 每个生命周期里又有多个阶段。当执行某个阶段时,这个阶段的后面各个阶段也会依次执行。

Clean 生命周期

PhaseDescription
pre-clean在实际项目清理之前执行
clean删除上一个版本生成的所有文件
post-clean执行完成项目清理后执行

Default 生命周期

由于Default的生命周期比较多,下面只列出几个常用的

PhaseDescription
generate-resources生成包含在包中的资源
compile编译项目的源代码。
test使用合适的单元测试框架运行测试
package编译代码并将其打包, 例如JAR
install将软件包安装到本地存储库中

Site 生命周期

PhaseDescription
pre-site在实际项目站点生成之前执行所需的过程
site生成项目的站点文档
post-site执行完成站点生成所需的流程,并准备站点部署
site-deploy将生成的站点文档部署到指定的Web服务器

关于生命周期更多详情可以去查看官网:生命周期详解【官网】

超级POM

超级POM是Maven的默认POM,除非有明确的设置,否则所有的POM都继承与超级POM。

像Maven生成的/ src / main / java/ src / test / java 等等其他路径,都是有超级POM来实现的。

超级POM的位置在:apache-maven-3.5.0\lib\maven-model-builder-3.5.0.jar包中。

pom-4.0.0.xml

<?xml version="1.0" encoding="UTF-8"?>
<project>
  <modelVersion>4.0.0</modelVersion>

  <repositories>
    <repository>
      <id>central</id>
      <name>Central Repository</name>
      <url>https://repo.maven.apache.org/maven2</url>
      <layout>default</layout>
      <snapshots>
        <enabled>false</enabled>
      </snapshots>
    </repository>
  </repositories>

  <pluginRepositories>
    <pluginRepository>
      <id>central</id>
      <name>Central Repository</name>
      <url>https://repo.maven.apache.org/maven2</url>
      <layout>default</layout>
      <snapshots>
        <enabled>false</enabled>
      </snapshots>
      <releases>
        <updatePolicy>never</updatePolicy>
      </releases>
    </pluginRepository>
  </pluginRepositories>

  <build>
    <directory>${project.basedir}/target</directory>
    <outputDirectory>${project.build.directory}/classes</outputDirectory>
    <finalName>${project.artifactId}-${project.version}</finalName>
    <testOutputDirectory>${project.build.directory}/test-classes</testOutputDirectory>
    <sourceDirectory>${project.basedir}/src/main/java</sourceDirectory>
    <scriptSourceDirectory>${project.basedir}/src/main/scripts</scriptSourceDirectory>
    <testSourceDirectory>${project.basedir}/src/test/java</testSourceDirectory>
    <resources>
      <resource>
        <directory>${project.basedir}/src/main/resources</directory>
      </resource>
    </resources>
    <testResources>
      <testResource>
        <directory>${project.basedir}/src/test/resources</directory>
      </testResource>
    </testResources>
    <pluginManagement>
      <!-- NOTE: These plugins will be removed from future versions of the super POM -->
      <!-- They are kept for the moment as they are very unlikely to conflict with lifecycle mappings (MNG-4453) -->
      <plugins>
        <plugin>
          <artifactId>maven-antrun-plugin</artifactId>
          <version>1.3</version>
        </plugin>
        <plugin>
          <artifactId>maven-assembly-plugin</artifactId>
          <version>2.2-beta-5</version>
        </plugin>
        <plugin>
          <artifactId>maven-dependency-plugin</artifactId>
          <version>2.8</version>
        </plugin>
        <plugin>
          <artifactId>maven-release-plugin</artifactId>
          <version>2.3.2</version>
        </plugin>
      </plugins>
    </pluginManagement>
  </build>

  <reporting>
    <outputDirectory>${project.build.directory}/site</outputDirectory>
  </reporting>

  <profiles>
    <!-- NOTE: The release profile will be removed from future versions of the super POM -->
    <profile>
      <id>release-profile</id>

      <activation>
        <property>
          <name>performRelease</name>
          <value>true</value>
        </property>
      </activation>

      <build>
        <plugins>
          <plugin>
            <inherited>true</inherited>
            <artifactId>maven-source-plugin</artifactId>
            <executions>
              <execution>
                <id>attach-sources</id>
                <goals>
                  <goal>jar</goal>
                </goals>
              </execution>
            </executions>
          </plugin>
          <plugin>
            <inherited>true</inherited>
            <artifactId>maven-javadoc-plugin</artifactId>
            <executions>
              <execution>
                <id>attach-javadocs</id>
                <goals>
                  <goal>jar</goal>
                </goals>
              </execution>
            </executions>
          </plugin>
          <plugin>
            <inherited>true</inherited>
            <artifactId>maven-deploy-plugin</artifactId>
            <configuration>
              <updateReleaseInfo>true</updateReleaseInfo>
            </configuration>
          </plugin>
        </plugins>
      </build>
    </profile>
  </profiles>

</project>

迷你POM

在Maven中,对于POM最低要求如下:

  1. project 根标签
  2. modelVersion 设置为4.0.0,表示继承与超级POM 4.0.0版本
  3. groupId 项目组ID
  4. artifactId 项目名
  5. version 当前项目的版本

根据最低要求,写出的POM是下面这个样子的。

<project>
  <modelVersion>4.0.0</modelVersion>
  <groupId>com.demo.app</groupId>
  <artifactId>my-app</artifactId>
  <version>1.0.0</version>
</project>

总结

Maven是个很强大的构建工具,熟悉的使用可以加快对项目的效率。同时也要理解他们直接的依赖关系,除此之外Maven的功能远不过于此。像自定义插件、自定义骨架等特性,在下期说吧。

Logo

CSDN联合极客时间,共同打造面向开发者的精品内容学习社区,助力成长!

更多推荐