Java 服务器开发必备系列 —— Maven

Posted 何乐不为呢

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Java 服务器开发必备系列 —— Maven相关的知识,希望对你有一定的参考价值。

引言

最近开始学习 Spring Boot ,由于选用 Maven 作为构建工具,这也是 Java 后端开发常用的构建工具,当然也可以选用 Gradle ,Gradle 之前在 android 项目中使用居多,但近期也渐渐有取代 Maven 的趋势,后续可能会专门再写一篇关于 Gradle 的使用。这里先大致了解 Maven 管理项目的一些基础知识,这里主要参考官方的文档。


Maven简介

Maven 是一个项目管理和整合工具,为开发者提供了一套完整的构建生命周期框架。此工具简化和标准化了构建过程,有助于团队开发中完成如下工作:构建、文档、报告、依赖、scms、发布和分发等。


1. pom.xml

Maven 工程结构和内容通过一个 xml 文件来定义,即 pom.xml ,后续将详细说明此文件。

此外,由于 Maven 设计的理念 Conversion over configuration ,使用了约定大于配置的方式来定义构建过程,只要遵循默认的文件结构,在 pom.xml 中并不需要定义任何目录相关的配置。需要开发者定义的也只是生命周期目标和工程依赖,而且大部分工程管理和构建任务都是由 Maven 插件完成的。


2. Artifact(工具)

又或者可以将其成为模块,可以大致理解为一个项目最终生成的文件,可以是一个 jar/war 文件、源文件或二进制文件,甚至可以是一个 pom 文件。而每个 Artifact 都是通过 groudId:artifactId:version 作为标识来唯一确定的。假如希望一个 artifact 能够在其他项目中被使用,可以将其放到本地仓库中(通过 mvn install 实现);假如希望开放一个 artifact 给所有开发者使用,也可以将其提交到 Maven 的远程仓库中。


3. Repositories(仓库)

其实就是用来存储 artifact 的,分为本地仓库和远程仓库:

  • 本地仓库:是指个人电脑上的指定目录,默认是系统用户目录下的 .m2/repository 目录下,也可以通过 maven 安装目录下的 conf/setting.xml 中的标签来自定义;

  • 远程仓库:远程服务器上用来存储 artifact 的仓库,默认是指向 maven 的服务器仓库,也可以通过 maven 安装目录下的 conf/setting.xml 中的标签来指向其他源服务器。

项目中引用本地或远程仓库中 artifact 时,只需要在 pom.xml 中声明 dependency 即可,在编译代码时,maven 会自动根据依赖信息去下载对应的 artifact 。


4. build Lifecycles (构建生命周期)

Maven 设了标准的项目构建生命周期,分为三类

  • default LifeCycle

    处理项目的部署

  • clean LifeCycle

    处理项目的清理

  • site LifeCycle

    处理项目的文档生成

每一类生命周期,其实都包含了若干个 phase ,这里以 default LifeCycle 为例,其完整的 phase 如下:

<phases>
 <phase>validate</phase>
 <phase>initialize</phase>
 <phase>generate-sources</phase>
 <phase>process-sources</phase>
 <phase>generate-resources</phase>
 <phase>process-resources</phase>
 <phase>compile</phase>
 <phase>process-classes</phase>
 <phase>generate-test-sources</phase>
 <phase>process-test-sources</phase>
 <phase>generate-test-resources</phase>
 <phase>process-test-resources</phase>
 <phase>test-compile</phase>
 <phase>process-test-classes</phase>
 <phase>test</phase>
 <phase>prepare-package</phase>
 <phase>package</phase>
 <phase>pre-integration-test</phase>
 <phase>integration-test</phase>
 <phase>post-integration-test</phase>
 <phase>verify</phase>
 <phase>install</phase>
 <phase>deploy</phase>
</phases>

这些 phase 都是有序的,也就是每个 phase 必须等待前面的 phase 都执行完了才会执行。

当然,我们可以执行 mvn 命令来指定执行目标 phase (也称为 goal ,每个 phase 都可以作为 goal),即只执行至某个 phase ,例如我们后面会提及的工程编译命令 mvn compile ,其实就是指定执行目标 phase 为 compile ,而在这个过程会将此 phase 之前的 validate 、initialize 、generate-sources 、process-sources 、generate-resources 和 process-resources 这里个 phase 都执行了,再执行 compile ,而此 phase 之后的 phase 则不会被执行到。

default LifeCycle 中比较重要的 phase :


alidate #验证项目是否正确以及必须的信息是否可用
compile #编译源代码
test #测试编译后的代码,即执行单元测试代码
package #打包编译后的代码,在target目录下生成package文件
integration-test #处理package以便需要时可以部署到集成测试环境
verify #检验package是否有效并且达到质量标准
install #安装package到本地仓库,方便本地其它项目使用
deploy #部署,拷贝最终的package到远程仓库和替他开发这或项目共享,在集成或发布环境完成

Maven 中的构建生命周期其实也是 Maven 最为人诟病的地方,因为把周期限制死了,无法根据实际情况添加新的 phase ,而只能将插件绑定到已有的 phase 上。


安装和配置

1. 安装配置

在 Windows 系统下安装配置 Maven 其实很简单,直接在官网下载安装包,解压缩到本地,再将其 bin 目录绝对路径配置到系统环境变量 PATH 中即可。步骤如下:

  • 下载最新的压缩包,例如:apache-maven-3.6.0-bin.zip

  • 解压然后将解压后的 bin 目录配置到系统环境变量;

  • 在命令行输入 mvn -v / mvn --version 测试是否安装成功,假如操作无误,则会输出如下:


    Apache Maven 3.6.0 (97c98ec64a1fdfee7767ce5ffb20918da4f719f3; 2018-10-25T02:41:47+08:00)
    Maven home: E:\Java\Installs\apache-maven-3.6.0\bin\..
    Java version: 1.8.0_144, vendor: Oracle Corporation, runtime: D:\Android\JDK1.8\jre
    Default locale: zh_CN, platform encoding: GBK
    OS name: "windows 7", version: "6.1", arch: "amd64", family: "windows"


2. 本地仓库配置


<localRepository>E:\Java\Workplace\Maven\repo</localRepository>


3. 远程仓库配置


<mirror>
   <id>alimaven</id>
   <mirrorOf>central</mirrorOf>
   <name>aliyun maven</name>
   <url>http://maven.aliyun.com/nexus/content/groups/public/</url>
</mirror>


pom.xml 管理文件

项目对象模型和 POM 是 Maven 的基本工作单元, pom.xml 文件包含了 Maven 构建工程时所需的工程和配置信息,也包含了大多数工程构建的默认配置信息,是使用 Maven 来管理的项目必不可少的文件。

查看 POM 官方文档 ,而标签的各种具体使用说明,也可查看 Guide to Configuring Plug-ins


Maven 基本命令

作为一个项目管理工具,我们至少需要了解如何创建、构建和打包工程。

1. 创建工程

Maven 使用原型(archetype)插件来创建工程,此插件实际上是从现有的 Maven 模板列表中挑选出一个作为原型,从而生成项目,接下来我们尝试生成一个 demo 工程,在命令行输入如下命令:


$ mvn archetype:generate
-DgroupId=com.linsh.test #工程包名
-DartifactId=mvn_demo #工程名称
-DarchetypeArtifactId=maven-archetype-quickstart
-DarchetypeVersion=1.4
-DinteractiveMode=false

这里几个参数的意义大致是:

  • DgroupId 工程的 groudId ,DartifactId 工程的 artifactId ,与后面的 DarchetypeVersion 三个参数结合起来在 Maven 仓库中作为模块的唯一标示;

  • DarchetypeArtifactId 是用于创建项目的原型模板的 artifactId ,这里我们选择的 maven-archetype-quickstart 适用于创建 Java 项目,假如要创建一个 Java Web 的项目,只需选择 maven-archetype-webapp 模板即可;

  • DarchetypeVersion 是模板的版本(有时也可以忽略,默认使用最新的版本);

  • DinteractiveMode 是否使用交互模式(由用户填写版本信息等,不使用则采用默认值)。

假如创建成功则可以看到如下输出:


[INFO] Scanning for projects...
[INFO]
[INFO] ------------------< org.apache.maven:standalone-pom >-------------------
[INFO] Building Maven Stub Project (No POM) 1
[INFO] --------------------------------[ pom ]---------------------------------
[INFO]
[INFO] >>> maven-archetype-plugin:3.0.1:generate (default-cli) > generate-sources @ standalone-pom >>>
[INFO]
[INFO] <<< maven-archetype-plugin:3.0.1:generate (default-cli) < generate-sources @ standalone-pom <<<
[INFO]
[INFO]
[INFO] --- maven-archetype-plugin:3.0.1:generate (default-cli) @ standalone-pom ---
[INFO] Generating project in Batch mode
[INFO] ----------------------------------------------------------------------------
[INFO] Using following parameters for creating project from Archetype: maven-archetype-quickstart:1.4
[INFO] ----------------------------------------------------------------------------
[INFO] Parameter: groupId, Value: com.linsh.test
[INFO] Parameter: artifactId, Value: mvn_demo
[INFO] Parameter: version, Value: 1.0-SNAPSHOT
[INFO] Parameter: package, Value: com.linsh.test
[INFO] Parameter: packageInPathFormat, Value: com/linsh/test
[INFO] Parameter: version, Value: 1.0-SNAPSHOT
[INFO] Parameter: package, Value: com.linsh.test
[INFO] Parameter: groupId, Value: com.linsh.test
[INFO] Parameter: artifactId, Value: mvn_demo
[INFO] Project created from Archetype in dir: E:\Java\Workplace\projects\TestMaven\mvn_demo
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time:  11.258 s
[INFO] Finished at: 2019-01-17T10:40:05+08:00
[INFO] ------------------------------------------------------------------------

此时,在命令行当前所在目录下,会创建一个名称为 mvn_demo(与设置的 artifactId 参数值对应)的工程目录。


2. 编译工程


$ mvn compile # 或者 mvn compiler:compile

执行此命令后,工程中 src/main 目录下的 Java 源码会编程生成对应的 .class 文件到目录 target/classes 之下,假如想要编译 src/test 下的源码,可以使用如下命令:


$ mvn test-compile # 或者 mvn compiler:testCompile

编译结果放在 target/test-classes 目录下。

从 3.0 版本开始,maven 默认的编译器就是 javax.tools.JavaCompiler ,用于编译 Java 源码,假如想使用 javac 来编译,可以在编译命令中设置参数 forceJavacCompilerUse


$ mvn compile -Dmaven.compiler.forceJavacCompilerUse=true

除此之外,maven 目前还支持其他的编译器,例如:AspectJ.NETC#


3. 清理缓存


$ mvn clean

用于清理编译和打包生成的缓存文件,其实就是把 target 目录删除掉。通常在执行打包命令之前会先调用此命令清理缓存文件,从而保证打出的包是最新的。

有时候,假如需要在每次构建工程的时候自动执行一次 clean 命令,且无需设置清理参数,可以直接在 pom.xml 中的 <artifactId>maven-clean-plugin</artifactId> 标签之后添加自动清理设置,如下:

<project>
 [...]
 <build>
   <plugins>
     <plugin>
       <artifactId>maven-clean-plugin</artifactId>
       <version>3.1.0</version>
       <executions>
         <execution>
           <id>auto-clean</id>
           <phase>initialize</phase>
           <goals>
             <goal>clean</goal>
           </goals>
         </execution>
       </executions>
     </plugin>
   </plugins>
 </build>
 [...]
</project>

如此,在工程每次构建的 initialize 阶段就会先自动执行清理命令。


4. 打包工程


$ mvn package

为了保险起见,通常在打包前先清理之前的缓存文件,所以打包命令通常如下:


$ mvn clean package

打包正常输出如下:


[INFO] Scanning for projects...
[INFO]
[INFO] ----------------------< com.linsh.test:mvn_demo >-----------------------
[INFO] Building mvn_demo 1.0-SNAPSHOT
[INFO] --------------------------------[ jar ]---------------------------------
[INFO]
[INFO] --- maven-clean-plugin:3.1.0:clean (default-clean) @ mvn_demo ---
[INFO] Deleting E:\Java\Workplace\projects\mvn_demo\target
[INFO]
[INFO] --- maven-resources-plugin:3.0.2:resources (default-resources) @ mvn_demo ---
[INFO] Using 'UTF-8' encoding to copy filtered resources.
[INFO] skip non existing resourceDirectory E:\Java\Workplace\projects\mvn_demo\src\main\resources
[INFO]
[INFO] --- maven-compiler-plugin:3.8.0:compile (default-compile) @ mvn_demo ---
[INFO] Changes detected - recompiling the module!
[INFO] Compiling 1 source file to E:\Java\Workplace\projects\mvn_demo\target\classes
[INFO]
[INFO] --- maven-resources-plugin:3.0.2:testResources (default-testResources) @ mvn_demo ---
[INFO] Using 'UTF-8' encoding to copy filtered resources.
[INFO] skip non existing resourceDirectory E:\Java\Workplace\projects\mvn_demo\src\test\resources
[INFO]
[INFO] --- maven-compiler-plugin:3.8.0:testCompile (default-testCompile) @ mvn_demo ---
[INFO] Changes detected - recompiling the module!
[INFO] Compiling 1 source file to E:\Java\Workplace\projects\mvn_demo\target\test-classes
[INFO]
[INFO] --- maven-surefire-plugin:2.22.1:test (default-test) @ mvn_demo ---
[INFO]
[INFO] -------------------------------------------------------
[INFO]  T E S T S
[INFO] -------------------------------------------------------
[INFO] Running com.linsh.test.AppTest
[INFO] Tests run: 1, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.02 s - in com.linsh.test.AppTest
[INFO]
[INFO] Results:
[INFO]
[INFO] Tests run: 1, Failures: 0, Errors: 0, Skipped: 0
[INFO]
[INFO]
[INFO] --- maven-jar-plugin:3.0.2:jar (default-jar) @ mvn_demo ---
[INFO] Building jar: E:\Java\Workplace\projects\mvn_demo\target\mvn_demo-1.0-SNAPSHOT.jar
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time:  2.052 s
[INFO] Finished at: 2019-01-19T12:39:53+08:00
[INFO] ------------------------------------------------------------------------

打包过程中完成的事情:

  • target 目录清理掉;

  • 编译工程中src 中的 main 目录下的工程源码和 test 目录下的测试源码;

  • 运行测试用例,并生成对应的测试报告到 target/surefire-reports 目录下;

  • 构建工程生成 jar 文件, jar 文件的命名规则是:(artifactId)-(version).jar 例如本工程生成的 mvn_demo-1.0-SNAPSHOT.jar ,而这两项参数其实都可以在 pom.xml 中进行修改。


其他

1. 常用命令

除了上述三个核心的命令之外,还有一些其他的常用命令,大致介绍如下:

  • mvn install :将当前工程作为模块安装到本地的 Maven 仓库中,如此便可在其他工程中以模块的方式引入此工程;

  • mvn site :生成项目相关信息的文档

此外,mvn 命令除了指定 goal 外,还能添加一些参数项来排查问题,常用的参数有:

  • -e 显示详细错误

  • -U 强制更新 snapshot 类型的插件或依赖库(否则maven一天只会更新一次snapshot依赖)

  • -o 运行 offline 模式,不联网更新依赖

  • -N 仅在当前项目模块执行命令,关闭 reactor

  • -pl module_name 在指定模块上执行命令

  • -ff 在递归执行命令过程中,一旦发生错误就直接退出

  • -Dxxx=yyy 指定java全局属性

  • -Pxxx 引用profile xxx


2. Junit 测试框架

看了 demo 工程不难发现,在 pom.xml 引入了 junit ,这其实是一个回归测试框架(只适用于  Java 工程),被开发者用于实施对应用程序的单元测试,加快程序编制速度,同时提高编码的质量。其实,查看 AppTest.java 中的源码,就会发现测试用例就是使用此框架来对应用进行单元测试的。


3. 搜索 Maven 模块


参考

  • Maven in 5 Minutes

  • Introduction to the POM

  • Maven Archetype

  • Maven Archetype Plugin/Usage

  • Apache Maven Compiler Plugin

  • Apache Maven Clean Plugin

  • Apache Maven Clean Plugin/Usage

  • Lifecycles Reference

  • Maven介绍,包括作用、核心概念、用法、常用命令、扩展及配置


以上是关于Java 服务器开发必备系列 —— Maven的主要内容,如果未能解决你的问题,请参考以下文章

Java后台开发必备软件(windows环境下)

2020 Java学习路线图,Java开发人员的必备技能

国内 Java 开发者必备的两个装备,你配置上了么?

Java工程师必备

Java开发系列05:Eclipse用Maven创建Web项目

Java系列讲座一:TCP方式Socket通信案例讲解