【Maven专栏系列】Maven项目从0到1

1,275 阅读8分钟

这是我参与11月更文挑战的第8天,活动详情查看:2021最后一次更文挑战

前言

本期内容是上期内容的一个延伸,小黑通过从0到1创建一个Maven项目,来实际操作一下。如果你也是初学Maven,也可以按照我的操作步骤来试试。

以下是本期的主要内容:

  1. 从0到1创建一个maven项目
  2. maven目录结构
  3. 常见maven命令
  4. 如何构建一个Fat Jar
  5. Maven内存设置

Maven hello world!

就叫这个项目maven-hello-world吧。

创建项目文件夹

一个Maven项目本质上就是pom文件和一个文件夹,我们先找一个位置,建立一个文件夹,就叫maven-hello-world

创建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>

    <groupId>com.heiz</groupId>
    <artifactId>maven-hello-world</artifactId>
    <version>1.0.0</version>

</project>

这是一个最基本的pom.xml文件。在这个文件中我们定义了这个项目的GAV(groupId,artifactId,version),别人如果需要依赖这个项目,则在依赖中加入我们的GAV就可以。

测试pom文件

现在为了保证我们文件的正确性,我们可以执行命令来测试一下。在当前目录打开命令行,然后执行下面的命令:

mvn clean

mvn clean命令将清除项目目录中所有以前的临时构建文件。因为我们的项目是全新的,所以没有文件需要删除。如果命令行输出下面的成功信息表示我们的pom.xml没问题。

创建Java源代码目录

接下来我们就可以建立Java源代码的文件目录了。按照如下层级建立文件夹。

- src
	- main
		-java

创建一个Java文件

然后我们在src/main/java文件夹中创建一个再创建一个文件夹作为我们代码的包,我们就叫它hello吧,然后再hello/建第一个Java代码文件HelloWorld.java

package hello;

public class HelloWorld {
	public static void main(String args[]){
		System.out.println("Hello World, Maven");
	}
}

构建项目

现在我们就可以使用Maven命令来打包我们的项目了。回到项目的根目录maven-hello-world。进入命令行执行下面的命令:

maven package

这个命令将将编译Java源文件,并创建一个包含已编译Java类的JAR文件。项目根目录中会创建一个target文件夹,JAR文件就存放在这个文件夹中,还有许多临时文件(例如,一个包含所有已编译类的类目录)。

image-20211105195103799

image-20211105195310190

JAR文件的命名格式为artifactId-version,所以我们的项目Jar包名称为maven-hello-world-1.0.0.jar

Maven目录结构

Maven有一套标准的目录结构,遵循这套标准很有用,也可以让别人在接手你的项目时更容易理解每个目录的作用。

标准目录结构

下面是一个最常用的maven目录结构,还有一些不太常用的目录我这里省略了。

project_dir
  - pom.xml
  - .mvn
    - jvm.config
  - src
    - main
      - java
      - resources
    - test
      - java
      - resources
  - target

project_dir是我们项目的根目录。

.mvn是一个存放Maven配置文件的目录,比如jvm.config文件,可用于配置Maven用于构建项目的JVM。可以在这个文件中设置Maven内存限制。

src是应用程序和测试源代码的根目录。

src/main/java存放应用程序的源代码。应用程序需要的任何资源文件(例如properties文件)都放在src/main/resources目录中。资源文件可以通过classpath加载。

src/test/java存放测试源代码。测试代码需要的任何资源文件(例如properties文件)都放在src/test/resources中。同样可以通过classpath加载。

target包含Maven构建项目的所有输出内容。target还包含Maven在构建应用程序时所需的临时文件和中间文件。

也可以访问maven官网查看更全的目录信息。maven官方文件目录说明

Maven命令

Maven包含大量可以执行的命令。Maven命令是Life Cycles、Phases和Goals的混合,因此有时候不太容易理解。因此,我将在本期内容中描述常见的Maven命令,并解释它们正在执行的Life Cycles、Phases和Goals。

常见的Maven命令

下面是一些常见的Maven命令,以及它们的功能描述。

maven命令Description
mvn --version打印maven版本
mvn clean清除target目录中的构建结果
mvn package构建项目并将生成的JAR文件放到target目录中。
mvn package -Dmaven.test.skip=true构建项目并将生成的JAR文件放到target目录中。——在构建期间不运行单元测试。
mvn clean package先清除target目录,然后构建项目并将生成的JAR文件放到target目录中。
mvn clean package -Dmaven.test.skip=true先清除target目录,然后构建项目并将生成的JAR文件放到target目录中。——在构建期间不运行单元测试。
mvn verify运行项目中所有的集成测试用例
mvn clean verify先清除target目录,然后运行项目中所有的集成测试用例
mvn install构建项目,并将生成的jar包保存到本地Maven仓库中
mvn install -Dmaven.test.skip=true构建项目,并将生成的jar包保存到本地Maven仓库中,构建时不运行单元测试
mvn clean install先清除target目录,构建项目,并将生成的jar包保存到本地Maven仓库中
mvn clean install -Dmaven.test.skip=true先清除target目录,构建项目,并将生成的jar包保存到本地Maven仓库中,构建时不运行单元测试
mvn dependency:copy-dependencies将依赖项从远程Maven仓库复制到本地Maven仓库。
mvn clean dependency:copy-dependencies清除项目并将依赖项从远程Maven仓库复制到本地Maven仓库。
mvn clean dependency:copy-dependencies package清除项目并将依赖项从远程Maven仓库复制到本地Maven仓库,然后打包项目。
mvn dependency:tree根据pom.xml文件中配置的依赖项,打印出项目的依赖项树。
mvn dependency:tree -Dverbose根据pom.xml文件中配置的依赖项,打印出项目的依赖项树。包括重复的传递依赖。
mvn dependency:tree -Dincludes=com.fasterxml.jackson.core打印出项目中依赖com.fasterxml.jackson.core的依赖项。
mvn dependency:tree -Dverbose -Dincludes=com.fasterxml.jackson.core打印出项目中依赖com.fasterxml.jackson.core的依赖项,包括重复的传递依赖。
mvn dependency:build-classpath根据pom.xml文件中配置的依赖项,输出依赖项的classpath。

需要注意,执行maven的clean命令时,会将target中的所有文件删除,这意味着会丢失之前已经编译构建过的类。如果项目很大,可能需要花费较多的时间构建。但是一般在项目部署之前,为了保证所有的内容都是重新构建的,一般都会执行clean。

Build Life Cycles, Phases和Goals

这三者的关系可以按下图表示:

Maven包含三个主要的Build Life Cycles

  • clean
  • default
  • site

在每个Build Life Cycles中都包含Phases,在每个Phases中都包含Goals

可以理解为Maven将需要做的事情按照粒度进行了划分,将Goals组合成Pahses,然后将Phases组合成Life cycles

构建一个Fat Jar

首先说一下什么是Fat Jar?这里我们还是用我们的maven-hello-world项目来举个例子。

假设我现在需要将Guava加入到我的项目依赖中,我们在pom.xml中添加Guava的依赖。

<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.heiz</groupId>
    <artifactId>maven-hello-world</artifactId>
    <version>1.0.0</version>

    <dependencies>
        <dependency>
            <groupId>com.google.guava</groupId>
            <artifactId>guava</artifactId>
            <version>18.0</version>
        </dependency>
    </dependencies>
</project>

然后我们使用mvn package进行打包。完成之后我们会在target目录中找到我们的maven-hello-world-1.0.0.jar,如果你使用解压工具打开看的话,这个Jar包中是没有guava包相关的文件的。

那么我们在某些场景中,比如需要发布一个微服务,如果没有将依赖项打包到一个JAR文件中,那么需要将其他依赖项单独的上传到服务中,这很麻烦。如果能够将所有的依赖和项目代码一起打包到一个JAR文件中,只需要上传一个文件就可以启动服务,这会很方便。

Fat JAR就是这种将所有依赖打包到一起的JAR文件。

要想构建一个Fat JAR,需要修改我们的pom.xml。通过在POM文件的plugins部分中包含maven-assembly-plugin:

<build>
    <finalName>maven-hello-world</finalName>
    <plugins>
        <!-- other Maven plugins ... -->
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-assembly-plugin</artifactId>
            <version>3.1.1</version>
            <configuration>
                <archive>
                    <manifest>
                        <!--这里指定要运行的main类-->
                        <mainClass>hello.HelloWorld</mainClass>
                    </manifest>
                </archive>
                <descriptorRefs>
                    <descriptorRef>jar-with-dependencies</descriptorRef>
                </descriptorRefs>
            </configuration>
            <executions>
                <execution>
                    <id>make-assembly</id>
                    <phase>package</phase>
                    <goals>
                        <goal>single</goal>
                    </goals>
                </execution>
            </executions>
        </plugin>
    </plugins>
</build>

maven-assembly-plugin配置中的元素包含descriptorRef,它告诉Maven怎样进行组装。

jar-with-dependencies表示构建一个带有依赖项的JAR文件,也就是Fat JAR。

execution表示这个插件应该在哪个阶段和目标执行。

将上面的配置添加到我们的maven-hello-world的pom.xml文件中,再执行一次mvn clean package。执行成功之后,在target目录中会出现一个Fat Jar。

Maven内存设置

如果要构建一个大型Maven项目,或者计算机的内存比较小,可能需要调整Maven的内存限制。从Maven 3.3版本,可以在jvm.config文件中设置内存限制。jvm.config位于项目目录中的.mvn目录中。

jvm.config文件中,可以使用以下参数控制Maven的内存限制:

-Xmx2048m -Xms1024m

可以通过调整-Xmx-Xms的值控制内存使用大小。

最后

以上是本期的全部内容,下期再专门讲一下Maven依赖相关的一些问题,如果对你有帮助,点个赞是对我最大的鼓励!