Maven 入门教程

Maven 这个词能够翻译为专家的意思。它是由 Apache 组织的开源,主要服务 Java 平台项目的构建、依赖管理和项目信息管理。php

有了 Maven 咱们只需编写一些配置而后运行一条命令就能够自动完成项目编译、测试、打包、发布等流程。前端

安装

Maven 须要依赖 Java 环境,因此首先要确认安装了 Java,首先去官网下载 Maven,而后就能够把它随便解压到一个文件夹,并把这个文件夹路径设置为 M2_HOME 环境变量,最后将 %M2_HOME%\bin(Windows)加入到 PATH,Linux 为 export PATH=$PATH:$M2_HOME/binjava

mvn -v # 在命令行运行这条命令,查看 Maven 版本
复制代码

对于升级就是重复上面的流程。node

Maven 安装目录下的 conf 文件下存放着 Maven 的配置 settings.xml,它的做用域是全局的,咱们能够复制它到 ~/.m2 下,用户目录下的 settings.xml 修改只对当前的用户有做用。Maven 的依赖包仓库放在,~/.m2 文件夹下的 repository 文件夹中。git

由于 Maven 实际上执行的是 Java 命令,咱们能够经过 MAVEN_OPT 环境变量设置它的参数。一般须要设置它的值为 -Xms128m -Xmx512m 由于对于大点的项目可能出现内存不够的错误。github

对于编辑器中的 Maven 咱们能够设置它使用咱们下载的 Maven,这样就能够避免两个 Maven 版本不一致而形成的构建行为不一致。web

入门

对于 Maven 项目,最核心的就是 pom.xml (Project Object Model) 咱们须要把项目的构建配置信息都写在里面。spring

<?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.0</modelVersion>
    <groupId>com.demo</groupId>
    <artifactId>hello-world</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>hello world project</name>
    <description>Demo project</description>
</project>
复制代码

第一行是 XML 头,指定了 XML 版本和文件编码。sql

而后就是 project 元素,它是配置文件的根元素,它还声明了 POM 的命名空间。docker

而后就是 modelVersion 对于 Maven2 和 Maven3 它只能是 4.0.0 版本。

groupId, artifactIdversion 定义了一个项目的基本坐标。

groupId 定义了项目属于哪一个组,它一般和 Java 中包名命名同样,例如 a 公司启动了一个 myapp 项目,那么他的 groupId 就多是 com.a.myapp

artifactId 定义了当前 Maven 项目在组中惟一的 ID,由于一个项目可能有多个子项目或模块。

version 指定了当前项目的版本。SNAPSHOT 为快照版本。

name 给项目更友好的名称,description 是对项目的描述。

上面这些字段定义了项目基本的信息,下面咱们就能够编写项目代码了。

package com.demo.helloworld;

public class HelloWorld {
    public String sayHello() {
        return "hello world";
    }

    public static void main(String[] args) {
        System.out.println(sayHello());
    }
}
复制代码

Maven 采用约定大于配置的方式,在大多数的状况下项目源码应该放在项目文件夹下的 src/main/java 下(Maven 会自动在该目录下搜寻源码),资源放在 src/main/resources 下,测试代码放在 src/test/java 下。

咱们的包名也应该和 groupIdartifactId 相吻合。

而后执行

mvn clean compile
复制代码

clean 是让 Maven 清除项目输出 target 目录。compile 任务用来将项目编译到 target/classes 目录下。

而后咱们用 JUnit 编写单元测试,首先须要在 pom.xml 加上 junit 的依赖。

<?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.0</modelVersion>
    <groupId>com.demo</groupId>
    <artifactId>hello-world</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>hello world project</name>
    <description>Demo project</description>

  <dependencies>
    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>4.11</version>
      <scope>test</scope>
    </dependency>
  </dependencies>

</project>
复制代码

引入一个依赖咱们须要填写它的基本坐标,有了这个坐标,Maven 就会自动取中央仓库下载,这个依赖到 ~/.m2/repository 文件夹下。

scope test 是表示依赖只对测试有效,在主代码中引入 junit 会报错。

package com.demo.helloworld;

import org.junit.Test;
import static org.junit.Assert.assertEquals;

public class HelloWorldTest {
    @Test
    public void test() {
        HelloWorld helloWorld = new HelloWorld();
        assertEquals("hello world", helloWorld.sayHello());
    }
}
复制代码

而后咱们须要对 Maven 的编译插件进行一些配置,由于它默认只支持 Java 1.5 因此咱们须要配置它为更高版本的 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.0</modelVersion>
    <groupId>com.demo</groupId>
    <artifactId>hello-world</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>hello world project</name>
    <description>Demo project</description>
    
    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> 
        <!-- 配置源码编码 -->
        <maven.compiler.source>1.8</maven.compiler.source>
        <maven.compiler.target>1.8</maven.compiler.target>
        <!-- 配置 Java 版本 -->
    </properties>

    <dependencies>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.11</version>
            <scope>test</scope>
        </dependency>
    </dependencies>

</project>
复制代码

而后执行

mvn clean test
复制代码

它会编译测试文件而后运行测试,最后咱们就可以看到测试经过的输出。

下一步就是对项目打包,由于咱们没有指定项目打包的类型,因此默认就是 jar

mvn clean package
复制代码

进行打包以前 Maven 会自动帮咱们编译,测试,经过了就打成 jar 包,放在 target 目录下,名称为 hello-world-0.0.1-SNAPSHOT.jar 它是根据 artifactIdversion 还有打包类型进行命名。

test 会自动帮咱们执行 compilepackage 会自动帮咱们执行 testinstall 会自动帮咱们执行 packageinstall 是将项目安装到仓库中。

咱们还可使用 archetype 插件来生成项目骨架,执行 mvn archetype:generate 命令就能够了,固然也可使用编辑器新建一个 Maven 项目来选择项目模板。

坐标

Maven 是经过坐标找到一个依赖的,而一组坐标是经过一些元素定义的。

  • groupId 一个组织的的一个实际项目
  • artifactId 实际项目中的一个 Maven 项目或模块
  • version 版本
  • packaging 打包方式有 jarwar
  • classifier 用来定义构建输出的附属构建 如 hello-world-1.0.0-javadoc.jar,它里面包含了 Java 文档,javadoc 就是就是附属构建的 classifier

前三个必须定义,packaging 默认 jarclassifier 不能直接定义。

依赖

一个项目依赖须要放在 dependencies 中,dependency 有几个子元素。

  • groupId, artifactIdversion 是项目基本坐标。
  • type 依赖类型,默认是 jar
  • scope 依赖范围
  • optional 是否可选
  • exclusions 用来排除传递依赖

其中依赖范围有几个值能够选。依赖范围主要是控制编译, 测试运行classpath

  • compile 默认,在编译,测试和运行都有效
  • test 只对测试 classpath 有效,如 junit 它只要在测试的时候能用到就行。
  • provided 对编译和测试有效,好比 servlet-api,由于运行时容器都会提供,因此无需重复引入。
  • runtime 运行时依赖,对测试和运行时有效,在编译时无效,好比 jdbc 驱动实现,只有在须要运行的时候在须要特定的驱动实现。
  • system 系统依赖范围,它与 provided 依赖范围彻底一致,只是它的依赖必须使用 systemPath 显式的指定依赖路径,它不是经过 Maven 仓库解析。
<dependencies>
        <dependency>
            <groupId>javax.sql</groupId>
            <artifactId>jdbc-stdext</artifactId>
            <version>2.0</version>
            <scope>system</scope>
            <systemPath>${java.home}/lib/rt.jar</systemPath>
        </dependency>
    </dependencies>
复制代码

还有一种 import 为导入依赖范围,不会对上面三个依赖范围产生影响。

传递性依赖

传递依赖就是好比咱们依赖 spring-core (compile) 可是 spring-core 依赖 commons-logging (compile),那么咱们的项目也依赖 commons-logging (compile)。有了这个机制,咱们就不用考虑 spring 依赖什么,没必要手动安装它的依赖,Maven 会自动将必要的间接依赖引入当前项目。spring boot 的起步依赖就是利用 Maven 的传递依赖。

依赖范围也会对传递依赖产生影响。

左侧表示直接依赖,上面是表明间接依赖,中间就表示传递依赖范围。

依赖调解

好比咱们项目传递依赖中有两个依赖是同样的可是它的版本不同,那么 Maven 就会看谁的路径最短,最短的优先。

若是它们是同样长的,Maven 就查看 POM 中的依赖声明谁在前面谁就优先。

可选依赖

若是咱们项目依赖 A(compile),A 依赖 B(compile) 和 C (compile),可是 BC 定义为可选的,那么依赖就不会被传递。依赖可选能够经过 <optional>true</optional> 指定。

排除依赖

若是咱们想排除一个传递依赖,好比 spring boot 默认是使用的 jackson,若是咱们想用 gson,那么咱们就能够将 jackason 排除,而后显式的引入 gson。

<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
        <exclusions>
            <exclusion>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-json</artifactId>
            </exclusion>
        </exclusions>
    </dependency>
    <dependency>
        <groupId>com.google.code.gson</groupId>
        <artifactId>gson</artifactId>
        <version>2.8.5</version>
    </dependency>
</dependencies>
复制代码

归并依赖

若是咱们依赖一个项目的不少模块,由于是一个项目因此版本号都是同样的,这样咱们就要给每一个依赖填写同样的版本号,升级的话又要一个一个的改。

这时候咱们就能够声明一个变量,而后其余地方直接使用就好了。

<?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.0</modelVersion>
    <groupId>com.demo</groupId>
    <artifactId>hello-world</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>hello world project</name>
    <description>Demo project</description>
    
    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <maven.compiler.source>1.8</maven.compiler.source>
        <maven.compiler.target>1.8</maven.compiler.target>
        <spring.version>2.5.6</spring.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-core</artifactId>
            <version>${spring.version}</version>
        </dependency>
        <!-- · · · -->
    </dependencies>

</project>
复制代码

${} 能够引入 Maven 的属性。

仓库

Maven 中任何一个项目或插件的输出都称为构件。任何构件都会有一个惟一的坐标。为了重用 Maven 的依赖都统一放在仓库中,而不是每一个项目都有个 lib 同样的文件夹来装它的依赖。

Maven 的仓库分为远程仓库和本地仓库,Maven 会首先经过坐标去本地仓库寻找依赖,若是没有就去远程仓库下载依赖,而后在放入本地仓库再使用。若是都没有的话那么就会报错。

咱们能够自定义远程仓库,Maven 自带了一个远程仓库,它包含绝大部分的构件,默认状况都会去这个中央仓库下载构件。

私服是另外一种远程仓库,为了节约宽带和时间,在局域网中搭建一个私有仓库,用其代理外部远程仓库,内部项目还能够安装到私服上供其余项目使用。

除了上面两种还有其余的公开远程仓库。好比 jboss repository 等。

本地仓库

本地仓库默认位置是当前用户目录下的 .m2/repository 文件夹,若是咱们想更改它的位置能够修改 .m2/settings.xml 文件。

<settings>

    <localRepository>D:\maven\repository</localRepository>

</settings>
复制代码

若是咱们本地有两个项目 AB ,项目 B 依赖于 A,那么咱们能够将项目 A 安装到本地仓库,这样咱们就能够在 B 项目中依赖 A 了,咱们能够在 A 项目中执行 mvn clean install 来将 A 项目安装到本地仓库。

远程仓库

Maven 须要知道最少一个远程仓库,这样 Maven 才能下载构件到本地。中央仓库就是默认的远程仓库,全部 Maven 项目 pom.xml 会继承一个超级POM,它就在 Maven 安装目录下的 lib/maven-model-builder-3.6.1.jar\org\apache\maven\model\ 文件夹,名为 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>

    <!-- · · · -->
</project>
复制代码

私服

私服是特殊远程仓库,它代理多个外部远程仓库,咱们使用私服来下载构件,私服上若是没有就会取远程下载,而后缓存起来。

配置

若是咱们须要的构件不在中央仓库而在另一个仓库,咱们就能够在 pom.xml 中配置该仓库。

<repositories>
    <repository>
        <id>jboss</id>
        <name>JBoss Repository</name>
        <url>http://repository.jboss.org/maven2/</url>
        <layout>default</layout>
        <releases>
            <enabled>true</enabled>
        </releases>
        <snapshots>
            <enabled>false</enabled>
        </snapshots>
    </repository>
</repositories>
复制代码

其中 id 必须时惟一的,若是有仓库声明和中央仓库同样的 id 就会覆盖它,url 就是仓库地址,releasessnapshots 分别用来控制发布版和快照版构件的下载,enabledtrue 表示开启下载,false 表示关闭下载。

快照版本是表示开发中的版本,开发中项目会平凡的变化,好比咱们开发一个项目中一个模块,可是它要依赖另外一个模块,咱们就将它安装到本地依赖,这样就能够在咱们项目中使用,可是若是依赖项目变了,可是咱们仍是会使用缓存本地的模块,这时候就要使用 snapshot 版本了,对于快照版本 Maven 每次会去检查当前是否是最新的,若是不是就下载最新的代码。

snapshots 能够设置 Maven 检查更新频率。

<snapshots>
    <updatePolicy>daily</updatePolicy>
    <checksumPolicy>ignore</checksumPolicy>
</snapshots>
复制代码

never 从不,always 每次构件都去检查,daily 天天(默认值)。

checksumPolicy 是 Maven 下载构件时会校验构件,默认时 warn 警告,还有 fail 项目构建会失败,ignore 忽略。

远程仓库验证

对于组织内部的仓库每每须要认证才运行访问,咱们能够在 settings.xml 中设置仓库的帐号和密码。

<servers>
    <id>repo</id>
    <username>username</username>
    <password>password</password>
</servers>
复制代码

其中 id 和咱们定义远程仓库 id 对应。

部署到远程仓库

私服的一个做用就是用来部署第三方构件,Maven 能够帮助咱们将构件部署到仓库中。

<project>
    <distributionManagement>
        <repository>
            <id>id</id>
            <name>Release Repository</name>
            <url>http://196.0.0.1/path/to/release</url>
        </repository>
        <snapshotRepository>
            <id>snapshot</id>
            <name>Snapshot Repository</name>
            <url>http://196.0.0.2/path/to/release</url>
        </snapshotRepository>
    </distributionManagement>
</project>
复制代码

repository 表示发布版的仓库,snapshotRepository 表示快照仓库,id 是惟一标识,咱们能够经过它来设置帐号和密码。

而后咱们能够执行以下命令发布

mvn clean deploy
复制代码

仓库解析依赖机制

当依赖返回是 system 时 Maven 回去本地寻找。

当是显式版构件时 如 1.2, 1.3-beta-1 等,Maven 会去全部远程仓库下载到本地。

当依赖版本是 RELEASE LATESTSNAPSHOT 时会根据更新策略去全部远程仓库搜寻构件元数据,而后和本地的元数据合并,再经过合并后的值取寻找版本。

镜像

咱们还能够在 settings.xml 中设置镜像镜像服务器。

<mirrors>
    <mirror>
        <id>maven.net.cn</id>
        <name> maven central mirror</name>
        <url>http://maven.net.cn/content/groups/public/</url>
        <mirrorOf>central</mirrorOf>
    </mirror>
</mirrors>
复制代码

咱们上面给中央仓库设置一个镜像,咱们也能够设置 mirrorOf* 表示匹配全部远程仓库。

生命周期和插件

Maven 有 3 套生命周期,分别是 cleandefaultsite,Maven 的生命周期是抽象的存在,就像一个接口,它把实际工做交给个插件。这 3 套生命周期是相互独立的。

每一个生命周期都有一些阶段(phase),如 clean 生命周期有 3 个阶段,pre-clean, cleanpost-clean,阶段是有顺序的,当执行 clean 阶段,会执行它前面的 pre-clean

clean 生命周期的阶段一共有

  1. pre-clean 执行清理前须要执行的工做
  2. clean 清理上次构件
  3. post-clean 清理事后须要执行的操做

default 生命周期是最核心的部分,它一共有以下阶段

  1. validate
  2. initialize
  3. generate-sources
  4. process-sources 处理主资源文件,通常是 src/main/resources 目录下的文件。
  5. generate-resources
  6. process-resources
  7. compile 编译项目源码。
  8. process-classes
  9. generate-test-sources
  10. process-test-sources 处理项目测试资源文件。
  11. generate-test-resources
  12. process-test-resources
  13. test-compile 编译测试源码
  14. process-test-classes
  15. test 使用单元测试框架运行测试。
  16. prepare-package
  17. package 接受编译好的代码,打包成可发布格式。
  18. pre-integration-test
  19. integration-test
  20. post-integration-test
  21. verify
  22. install 将包安装到 Maven 本地仓库,供本地其余项目使用
  23. deploy 将包复制到远程仓库。

site 生命周期目的是创建和发布项目站点。

  1. pre-site 生成站点以前要执行的操做
  2. site 生成项目站点文档
  3. post-site 执行生成站点以后要完成的工做
  4. site-deploy 将站点发布到服务器

命令行

执行 Maven 任务主要方式就是调用 Maven 的生命周期阶段。

mvn clean 就是执行 clean 生命周期的 clean 阶段

mvn test 就是执行 default 生命周期的 test 阶段

mvn clean install 就是执行 clean 生命周期 clean 阶段和 defaultinstall 阶段。

插件目标

Maven 只是定义了生命周期,然而实际的工做仍是要交给插件。一个插件会有一个或多个目标(goal)每一个目标对应一个功能,如 surefire:test surefire 是插件名,test 是插件目标,surefire 是 Maven 默认测试插件。

Maven 的生命周期的阶段和插件的目标相互绑定,来完成实际任务。

Maven 默认为主要的生命周期阶段绑定了不少插件目标,当调用生命周期阶段时,相应的插件就会被执行。

自定义绑定

<build>
    <plugins>
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-source-plugin</artifactId>
            <version>2.1.1</version>
            <executions>
                <execution>
                    <id>attach-sources</id>
                    <phase>verify</phase>
                    <goals>
                        <goal>jar-no-fork</goal>
                    </goals>
                </execution>
            </executions>
        </plugin>
    </plugins>
</build>
复制代码

上面咱们将 maven-source-pluginjar-no-fork 目标绑定到了 verify 阶段。id 为任务名。

插件配置

插件也有参数,咱们能够经过命令行或在 pom.xml 设置它的参数。

咱们能够经过 -D参数键=参数值 来设置插件目标参数,如 mvn package -Dmaven.test.skip=true -D 是 Java 自带的,用来设置 Java 系统属性,Maven 只是重用了该参数。

pom.xml 中咱们能够经过 configuration 设置参数。

<build>
    <plugins>
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-compiler-plugin</artifactId>
            <version>3.8.1</version>
            <configuration>
                <source>1.8</source>
                <target>1.8</target>
            </configuration>
        </plugin>
    </plugins>
</build>
复制代码

除了在外层设置插件参数(全局),咱们还能够对一个 execution 设置参数。

<build>
    <plugins>
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-antrun-plugin</artifactId>
            <version>1.3</version>
            <executions>
                <execution>
                    <id>ant-validate</id>
                    <phase>validate</phase>
                    <goals>
                        <goal>run</goal>
                    </goals>
                    <configuration>
                        <tasks>
                            <echo>lalala</echo>
                        </tasks>
                    </configuration>
                </execution>
            </executions>
        </plugin>
    </plugins>
</build>
复制代码

命令行调用插件

咱们还能够经过命令行调用插件目标。

mvn [options] [goal<s>] [phase[s]]
复制代码

由于有些插件目标不适合绑定到生命周期阶段执行,因此咱们能够直接在命令行执行插件的目标。

mvn dependency:tree # 查看项目依赖
# 固然咱们将插件的 groupId artifactId version 都写上
复制代码

咱们知道插件有它的基本坐标,Maven 是如何经过 dependency 查到对应的插件呢?

由于 dependencymaven-dependency-plugin 插件的前缀,Maven 能够经过前缀查找到对应的 artifactId。Maven 会经过本地仓库查找插件,若是查不到就会取远程仓库查找。

对于未指定 groupId 的插件,Maven 会默认使用 org.apache.maven.plugins 做为它的 groupId。Maven 在超级POM 中设定了核心插件的版本,咱们项目中就能够继承到这些版本的设定,而无需本身设置。

若是一个插件既不是核心插件又没有设定版本,那么会检查全部仓库可用版本,而后作出选择。

聚合与继承

Maven 还支持多模块开发,咱们一个项目可能有不少的模块,Maven 能够将它们聚合在一块儿。

假如咱们有一个项目 app,它分为 a、b 和 c 三个模块,也就是三个 Maven 项目,由于它们是一个项目因此它们的 groupIdversion 都是同样的。

咱们项目目录可能像下面这样。

|-app
    |- a
        |- src
        |- pom.xml
    |- b
        |- src
        |- pom.xml
    |- c
        |- src
        |- pom.xml
    pom.xml
复制代码

咱们最外层有一个 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 http://maven.apache.org/xsd/maven-4.0.0.xsd" >
    <modelVersion>4.0.0</modelVersion>
    <groupId>com.demo.app</groupId>
    <artifactId>app-aggregator</artifactId>
    <version>1.0-SNAPSHOT</version>
    <packaging>pom</packaging>
    <modules>
        <module>a</module>
        <module>b</module>
        <module>c</module>
    </modules>
</project>
复制代码

须要将 packaging 设置为 pom,而后设定它要聚合的模块。

module 中是模块的相对路径,若是和其余模块是平行目录则路径就是 ../a 等。

如今咱们就不用一个一个取构件了,咱们在最外层执行 mvn clean install。Maven 会解析 pom.xml 并计算出模块的构建次序,而后顺序执行。

继承

咱们发现咱们的子模块有不少相同的配置,这时候咱们就可使用继承来消除重复。

咱们能够再建立一个用来作 parentpom.xml 也能够重用咱们上面建立的 aggregator pom.xml,若是重用的话咱们就无需修改它,可是须要修改要继承它的模块。

<!-- a 模块 -->

<?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 http://maven.apache.org/xsd/maven-4.0.0.xsd" >
    <modelVersion>4.0.0</modelVersion>
    <artifactId>app-a</artifactId>
    <parent>
        <groupId>com.demo.app</groupId>
        <artifactId>app-aggregator</artifactId>
        <version>1.0-SNAPSHOT</version>
        <relativePath>../pom.xml</relativePath>
    </parent>
</project>
复制代码

咱们使用 parent 来指明模块要继承的父级。这里的 relativePath 的默认值就是 ../pom.xml 咱们也能够省略它。

如今咱们继承了父级的 groupIdversion,若是咱们须要不一样的值,也能够覆盖它。几乎全部的项目均可以继承父级的。

若是咱们父级声明了一个依赖,那么全部子模块都会继承这个依赖,即便有的模块不须要这个依赖。

Maven 提供了 dependencyManagement 来让子模块不会引入实际依赖,只有子模块声明才会依赖。

<dependencyManagement>
    <dependencies>
      <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot</artifactId>
        <version>2.1.7.RELEASE</version>
      </dependency>
      <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-test</artifactId>
        <version>2.1.7.RELEASE</version>
      </dependency>
      <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-test-autoconfigure</artifactId>
        <version>2.1.7.RELEASE</version>
      </dependency>
    </dependencies>
</dependencyManagement>
复制代码
<!-- a 模块 -->
<dependencies>
  <dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot</artifactId>
  </dependency>
</dependencies>
复制代码

有了 dependencyManagement,咱们子模块不会直接继承,可是若是声明了须要继承就无需填写依赖的版本了。

spring boot 就是利用 Maven 的继承,我许让咱们本身填写依赖的版本。

还有一个 pluginManagement (在 build 元素下) 它的做用和 dependencyManagement 是同样的,只是它是做用于插件。

测试

Maven 的测试是使用 maven-surefire-plugin 插件。

有时候咱们想跳过测试能够在命令行加入 -DskipTests-Dmaven.test.skip=true 不只跳过测试,也会跳过测试代码的编译。

咱们还能够运行指定测试,如 -Dtest=*Tests 表示只运行 Tests 结尾的测试,* 匹配 0 或多个字符。还可使用 , 分割多个参数,如 -Dtest=*Tests,*IT

Maven 属性

Maven pom.xml 中可使用 ${} 来注入属性,它一共支持 6 类属性。

  • 内置属性,如 ${version} 项目版本 和 ${basedir} 项目根目录
  • POM 属性,能够引用 pom.xml 中的属性,如 ${project.version}, ${project.build.sourceDirectory}
  • 自定义属性,在 properties 中自定义的属性
  • settings.xml 中的属性,如 ${settings.loaclRepository}
  • Java 系统属性,如 ${user.name}
  • 环境变量,如 ${JAVA_HOME}

Profile

咱们项目中开发环境和线上环境不一样每每须要不一样的配置。Maven 中的 Profile 就能够针对环境的不一样使用不一样的配置。

db.url=${db.url}
db.password=${db.password}
复制代码
<profiles>
    <profile>
      <id>dev</id>
      <activation> 
        <activeByDefault>true</activeByDefault> <!-- 配置默认激活 -->
      </activation>
      <properties>
        <db.url>dev.url</db.url>
        <db.password>dev.password</db.password>
      </properties>
    </profile>
    <profile>
      <id>prod</id>
      <properties>
        <db.url>prod.url</db.url>
        <db.password>prod.password</db.password>
      </properties>
    </profile>
</profiles>

<!-- 须要资源开启过滤,这样上面 properties 文件的 ${} 就能够注入咱们的 properties 中属性了 -->
<build>
    <resources>
        <resource>
            <directory>${project.basedir}/src/main/resources</directory>
            <filtering>true</filtering>
        </resource>
    </resources>
    <testResources>
        <testResource>
            <directory>${project.basedir}/src/test/resources</directory>
            <filtering>true</filtering>
        </testResource>
    </testResources>
</build>
复制代码

而后咱们就能够在命令行中使用 -Pdev 来激活开发模式的配置,profile 中的配置是当激活当前 profile 才会生效的配置。

frontend-maven-plugin

有时候咱们须要将前端和后端放在一块儿,咱们就可使用 frontend-maven-plugin , 来帮助咱们安装 node npm 或 yarn 来执行 npm script。

咱们只须要在前端模块中添加这个插件

<plugin>
    <groupId>com.github.eirslett</groupId>
    <artifactId>frontend-maven-plugin</artifactId>
    <version>${frontend-maven-plugin.version}</version>
    <configuration>
      <installDirectory>target</installDirectory> <!-- node 安装目录 -->
      <nodeVersion>v13.6.0</nodeVersion>
    </configuration>
    <executions>
      <execution>
        <id>install node and npm</id>
        <goals>
          <goal>install-node-and-npm</goal>
        </goals>
      </execution>
      <execution>
        <id>npm install</id>
        <goals>
          <goal>npm</goal>
        </goals>
        <configuration>
          <arguments>install</arguments>
        </configuration>
      </execution>
      <execution>
        <id>npm lint</id>
        <goals>
          <goal>npm</goal>
        </goals>
        <phase>compile</phase>
        <configuration>
          <arguments>run lint</arguments>
        </configuration>
      </execution>
      <execution>
        <id>npm run build</id>
        <goals>
          <goal>npm</goal>
        </goals>
        <phase>compile</phase>
        <configuration>
          <arguments>run build</arguments>
        </configuration>
      </execution>
      <execution>
        <id>npm run test</id>
        <goals>
          <goal>npm</goal>
        </goals>
        <phase>test</phase>
        <configuration>
          <arguments>run test</arguments>
        </configuration>
      </execution>
    </executions>
  </plugin>
复制代码

它会本身安装全新的 nodenpm ,与全局的 node 隔离。而后咱们使用它的 npm goal 来执行 npm 命令。 咱们也可使用 clean 插件来清理每次生成的代码。

<plugin>
    <artifactId>maven-clean-plugin</artifactId>
    <version>${maven-clean-plugin.version}</version>
    <executions>
      <execution>
        <id>remove existing output</id>
        <phase>compile</phase>
        <goals>
          <goal>clean</goal>
        </goals>
        <configuration>
          <excludeDefaultDirectories>true</excludeDefaultDirectories>
          <filesets>
            <fileset>
              <directory>build</directory>
            </fileset>
          </filesets>
        </configuration>
      </execution>
    </executions>
  </plugin>
复制代码

dockerfile-maven-plugin

dockerfile-maven-plugin 插件能够帮助咱们构建和发布 docker 镜像,而无需再手动输入命令。

<plugin>
    <groupId>com.spotify</groupId>
    <artifactId>dockerfile-maven-plugin</artifactId>
    <version>${dockerfile-maven-version}</version>
    <executions>
      <execution>
        <id>default</id>
        <goals>
          <goal>build</goal>
        </goals>
        <configuration>
          <contextDirectory>context</contextDirectory> <!-- 上下文目录 默认是当前目录 -->
          <dockerfile>not-context/Dockerfile</dockerfile> <!-- Dockerfile 地址,默认是当前目录下的 Dockerfile -->
          <buildArgs> <!-- docker build 命令参数 -->
            <IMAGE_VERSION>0.0.1</IMAGE_VERSION>
          </buildArgs>
        </configuration>
      </execution>
      <execution>
        <id>tag</id>
        <goals>
          <goal>tag</goal>
        </goals>
        <configuration>
          <repository>test/build-tag-version</repository> <!-- image 名称 -->
          <tag>${project.version}</tag> <!-- tag 版本 -->
          <skip>true</skip> <!-- 若是想跳过能够设置skip 为 true -->
        </configuration>
      </execution>
    </executions>
  </plugin>
复制代码

咱们须要一个 Dockerfile 来构建咱们的 image,若是是 spring boot 项目能够简单使用 fat jar 方法来构建。

FROM openjdk:8-jdk-alpine
VOLUME /tmp COPY target/*.jar app.jar ENTRYPOINT ["java","-jar","/app.jar"] 复制代码

更多关于 spring boot docker 能够查看 Spring Boot Docker

相关文章
相关标签/搜索