POM(project object model 项目对象模型) 定义了项目的基本信息、用于描述项目如何构建、声明项目依赖等等。

编写一个最简单的 pom.xml 文件

<?xml  version="1.0" encoding="UTF-8"?>
<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">

    <modelVersion>4.0.0modelVersion>
    
    <groupId>com.coderligroupId>
    <artifactId>business-adminartifactId>
    <version>1.0version>
    
    <name>business-adminname>
    <description>business-admindescription>
project>

<?xml  version="1.0" encoding="UTF-8"?>
<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">

    <modelVersion>4.0.0modelVersion>
    
    <groupId>com.coderligroupId>
    <artifactId>business-adminartifactId>
    <version>1.0version>
    
    <name>business-adminname>
    <description>business-admindescription>
project>

代码第一行是 XML 头、指定了该 xml 文档的版本和编码方式、紧接着是 project 元素、project 是所有 pom.xml 的根元素、它还声明了 POM 相关的命名空间及 xsd 元素。虽然这些属性不是必须的、但使用这些属性能够让第三方工具快速帮助我们编辑 POM 。

根元素的第一个个子元素 modelVersion 指定了当前 POM 模型的版本、对于 Maven2 及 Maven 3 来说、它只能是 4.0.0

这段代码中最重要的是包含了 groupId、artifactId 和 version 的三行、这三个元素定义了项目的基本坐标、在 Maven的世界中、任何的 jar、pom或者 war 都是基于这些基本的坐标进行区分的

groupId 定义了项目属于哪个组、这个组往往和项目所在的组织或公司存在关联。

artifactId 定义了当前 Maven 项目在组中的唯一 Id

version 指定了这个 artifact 项目当前的版本。

name 元素声明了一个对于用户更友好的项目名称、虽然不是必须的

description 元素声明了对这个项目的描述

编写主代码

项目主代码和测试代码不同、项目的主代码会被打包到最终的构建中、二测试代码只在运行测试时用到、不会被打包。

默认情况下、Maven 假设项目主代码位于 src/main/java 目录中、我们遵循 Maven的约定



maven自定义生成的target的文件夹名 maven中target_maven打包jar

创建一个 java 文件之后、我们 mvn clean compile

clean 告诉 Maven 清理输出目录 target/。默认情况下、Maven 构建的所有输出都在 target 目录中、接着执行resources:resources 任务、最好执行 compile:compile 任务、将项目主代码编译至 target/classes 目录

上面提到的 clean:clean、resources:resources 和 compile:compile 对应了一些 maven 插件及插件目标。比如说 clean:clean 是 clean 插件的 clean 目标,compile:compile 是 compile 插件的 compile 目标

编写测试代码

Maven 项目中默认的主代码目录是src/main/java 相应地、Maven 项目中默认的测试代码目录是 src/test/java/

<?xml  version="1.0" encoding="UTF-8"?>
<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">

    <modelVersion>4.0.0modelVersion>
    
    <groupId>com.coderligroupId>
    <artifactId>business-adminartifactId>
    <version>1.0version>
    
    <name>business-adminname>
    <description>business-admindescription>
    <dependencies>
      
      <dependency>
          <groupId>junitgroupId>
          <artifactId>junitartifactId>
          <version>4.13.1version>
          <scope>testscope>
      dependency>
    dependencies>
project>

<?xml  version="1.0" encoding="UTF-8"?>
<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">

    <modelVersion>4.0.0modelVersion>
    
    <groupId>com.coderligroupId>
    <artifactId>business-adminartifactId>
    <version>1.0version>
    
    <name>business-adminname>
    <description>business-admindescription>
    <dependencies>
      
      <dependency>
          <groupId>junitgroupId>
          <artifactId>junitartifactId>
          <version>4.13.1version>
          <scope>testscope>
      dependency>
    dependencies>
project>

在代码中添加了 dependencies 元素、该元素下可以包含多个 dependency 元素以声明项目的依赖。

groupId 是 junit、artifactId 是 junit、version 是 4.13.1 。

还有一个 scope 元素、值为 test、代表该依赖只对测试有效、换句话说、测试代码中引用 JUnit 代码没有问题、但是如果在主代码中引用 JUnit 代码、就会造成编译错误。如果不声明依赖范围、那么默认值就是 compile、表示该依赖对主代码和测试代码有效。

一个典型的单元测试包含三个步骤

  • 准备测试类及数据
  • 执行要测试的行为
  • 检查结果

在 JUnit 中约定需要执行测试的方法都以 test 开头

@Test
    public void testSayHello() {
        // 1. 准备
        HelloWorld helloWorld = new HelloWorld();
        // 2. 执行要测试的行为
        String result = helloWorld.sayHello();
        // 3. 检验结果
        Assert.assertEquals(result, "hello world");
    }

    @Test
    public void testSayHello() {
        // 1. 准备
        HelloWorld helloWorld = new HelloWorld();
        // 2. 执行要测试的行为
        String result = helloWorld.sayHello();
        // 3. 检验结果
        Assert.assertEquals(result, "hello world");
    }

输入命令mvn clean test ,maven 实际执行可不止这两个任务、还有clean:clean, resources:resources,compiler:compile,resources:testResources以及compiler:testCompile。

暂时需要了解的是、在 Maven 执行测试之前、它会先自动执行项目主资源处理、主代码编译、测试资源处理、测试代码编译等工作。这就是 Maven 生命周期的一个特性。



maven自定义生成的target的文件夹名 maven中target_maven打包jar_02

最后执行的是 surefire:test 、surefire 是 Maven 中负责执行测试的插件、这里它运行了测试用例 HelloWorldTest、并且输出了测试报告。

打包运行

将项目进行编译、测试之后、下一个步骤就是打包了 package。默认使用的打包类型 jar。可以使用 mvn clean package 进行打包

[INFO] Tests run: 8, Failures: 0, Errors: 0, Skipped: 0
[INFO]
[INFO]
[INFO] --- maven-jar-plugin:3.1.2:jar (default-jar) @ cp-business-admin ---
[INFO] Building jar: D:\project\business-admin\target\business-admin-1.0.jar
[INFO]
[INFO] --- spring-boot-maven-plugin:2.2.6.RELEASE:repackage (repackage) @ cp-business-admin ---
[INFO] Replacing main artifact with repackaged archive
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 50.495 s
[INFO] Finished at: 2020-10-30T16:24:42+08:00

[INFO] Tests run: 8, Failures: 0, Errors: 0, Skipped: 0
[INFO]
[INFO]
[INFO] --- maven-jar-plugin:3.1.2:jar (default-jar) @ cp-business-admin ---
[INFO] Building jar: D:\project\business-admin\target\business-admin-1.0.jar
[INFO]
[INFO] --- spring-boot-maven-plugin:2.2.6.RELEASE:repackage (repackage) @ cp-business-admin ---
[INFO] Replacing main artifact with repackaged archive
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 50.495 s
[INFO] Finished at: 2020-10-30T16:24:42+08:00

类似地、Maven 会在打包之前执行编译、测试等操作、这里看到 jar:jar 任务负责打包。实际上就是jar 插件地jar 目标将项目的主代码打包成一个名为 business-admin-1.0.jar 。该文件位于 target/ 输出目录中、文件名是 artifact-version.jar 组成的

当然可以将该jar 被其他 Maven项目直接引用 mvn clean install

在打包之后、又执行了 install:install 。可以看到该任务将输出的jar 安装到了 Maven 的本地仓库中。

[INFO] Installing D:\project\business-admin\target\business-admin-1.0.jar to C:\Users\YXL\.m2\repository\com\xxx\business-admin\1.0\business-admin-1.0.jar
[INFO] Installing D:\project\business-admin\pom.xml to C:\Users\YXL\.m2\repository\com\xxx\business-admin\1.0\business-admin-1.0.pom

[INFO] Installing D:\project\business-admin\target\business-admin-1.0.jar to C:\Users\YXL\.m2\repository\com\xxx\business-admin\1.0\business-admin-1.0.jar
[INFO] Installing D:\project\business-admin\pom.xml to C:\Users\YXL\.m2\repository\com\xxx\business-admin\1.0\business-admin-1.0.pom

执行 test 之前会执行 compile、执行 package 之前会执行 test、执行 install 之前会执行 package

默认打包生成的 jar 是不能够直接运行的、因为带有 main 方法的类信息不会添加到 manifest 中(打开 jar 文件中的 meta-inf/manifest.mf 文件、将无法看到 main-class 一行)。为了生成可执行的 jar 文件、需要借助 maven-shade-plugin

<plugin>
    <groupId>org.apache.maven.pluginsgroupId>
    <artifactId>maven-shade-pluginartifactId>
    <version>3.2.2version>
    <executions>
        <execution>
            <phase>packagephase>
            <goals>
                <goal>shadegoal>
            goals>
            <configuration>
                <transformers>
                    <transformerimplementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
                        <mainClass>com.example.MainmainClass>
                    transformer>
                transformers>
            configuration>
        execution>
    executions>
plugin>       

<plugin>
    <groupId>org.apache.maven.pluginsgroupId>
    <artifactId>maven-shade-pluginartifactId>
    <version>3.2.2version>
    <executions>
        <execution>
            <phase>packagephase>
            <goals>
                <goal>shadegoal>
            goals>
            <configuration>
                <transformers>
                    <transformerimplementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
                        <mainClass>com.example.MainmainClass>
                    transformer>
                transformers>
            configuration>
        execution>
    executions>
plugin>

plugin 元素在 POM 中相对位置是下面。我们配置了 mainClass 为 com.example.Main 、项目打包时会将该信息放到 manifest 中、现在执行 mvn clean install 待构建完成之后打开 target 目录、可以看到 xxx-1.0.snapshot.jar 和 original-xxx-1.0.snapshot.jar 、我们可以在xxx-1.0.snapshot.jar 中的meta-inf/manifest.mf 中看到里面的信息已经包含了 mainClass 信息了。

我们可以运行这个 jar

java -jar xxx-1.0.snapshot.jar

java -jar xxx-1.0.snapshot.jar

maven 的约定目录结构

  • 在项目的根目录中放置 pom.xml
  • 在src/main/java 目录中放置项目的主代码
  • 在src/test/java 目录中存放项目的测试代码
mvn archetype:generate

mvn archetype:generate

Archetype 事实上为 maven-archetype-quickstart 插件、创建的时候会提示你输入 groupId、artifactId、version。最终会在你当前目录创建一个名为文件夹(跟 artifact同名)。pom 中也包含了 JUnit 的依赖、然后创建一个 App.java 里面写着 Hello World。