文章目录



intro

今天 跑了一个项目 maven 这里出了各种 各样的项目

配了半天 还是 重学一下 maven 让自己能 标准的操作一个 java 工程

常用的 代码构建工具 有 ant,maven和gradle

我自己认为 目前比较主流的构建工具 还是 maven 然鹅 我司使用的构建工具是 gradle

Gradle与Maven相比更为灵活,

Hibernate就将自己的项目从Maven迁移到了Gradle,Google官方Android开发的IDE Android Studio也默认使用了Gradle进行构建。

未来可能就是 gradle 的天下了 不过 maven 目前还是主流 还需要好好了解一下 maven 至少现在宝刀未老 还有很强大的生命力

【重学maven】构建标准清晰地java工程_生命周期



构建工具:解放程序员的双手

先不局限在构建工具 maven自身,先了解下什么是构建工具

构建工具是指一个能够自动完成和软件项目构建相关的所有操作的工具。

构建一个软件项目通常包含下面的一步或多步。


  • 生成源码。
  • 生成源码中定义的文档。
  • 编译源码。
  • 将编译后的源码打包为 JAR 或 ZIP 格式文件。
  • 将源码打包成 JAR,运行在服务器、仓库或者其他位置。
  • 自动完成这些构建操作的好处是减少了手动操作时引发错误的风险,另外,自动构建往往比人手动操作要快捷许多。

Maven 的好处

Maven 最主要的目的是让开发人员花少量时间就能理解一个开发工作的完整状态。

为了达到这个目标,Maven 在以下几个方面做出了优化和改进。


  • 简化项目构建的流程。
    虽然使用 Maven 并非完全不需要了解其底层机制,
    但 Maven 屏蔽了许多的细节,
    让我们通过简单的命令就能使用。
  • 提供一个统一的构建系统。
    Maven 通过其项目对象模型(POM)和可以被所有项目共享的插件来为项目提供统一的构建机制。
    你只要熟悉一个 Maven 项目的构建流程,
    你就了解了所有 Maven 项目的构建流程,
    这为你在浏览其他许多项目时节省了大量的时间。
  • 提供完备的项目信息。
    Maven 提供了大量有用的项目信息,
    这些信息部分来自于项目的 POM 文件,
    部分来自于项目的源代码。

Maven 能够提供的信息如下。


  • 直接从代码管理软件中创建的更新日志。
  • 代码交叉引用。
  • 项目中管理的邮件列表。
  • 项目的依赖列表。
  • 单元测试报告以及覆盖率。

随着 Maven 的不断改进,这些信息的展示都会继续优化,对开发者而言都会是透明的。

同时,其他第三方产品也可以提供 Maven 插件来让他们项目的相关信息与 Maven 提供的信息一同展现出来,这也是基于 POM 的。

为各种项目开发提供最佳实践的引导。

Maven 旨在汇集所有开发的最佳实践来使新项目的引导指南更加简洁。

例如,单元测试的规范、执行和报告是使用 Maven 进行标准构建的一部分,

目前的单元测试最佳实践如下。


  • 将单元测试的代码与源代码分离,存放在同一级目录下。
  • 使用测试用例命名规范来定位和执行测试。
  • 让测试用例自行初始化其运行环境而不是依赖于自定义的构建。
  • Maven 还旨在协助项目工作流,例如项目的发布及问题的管理。

最后,Maven 也对项目的目录结构制定了相关的规范,

这样,开发者可以很轻松地掌握其他遵守了这一规范的项目的目录结构,省下大量的时间。

让开发者可以无感知升级来适配新特性。

Maven 提供了一个简单的方式来让 Maven 客户端进行更新和升级,

使开发者们可以不做任何改动就能享受到 Maven 的新特性。

安装其他第三方插件也因此变得简单了许多。

Maven的命根子pom.xml文件

Maven 的核心是 POM 文件,

POM 文件是一个用来表示项目资源的 XML 格式的文件,

它包含了项目的源码,测试代码和项目依赖(使用到的外部 JAR)等资源的引用

【重学maven】构建标准清晰地java工程_maven_02

Maven 如何使用 POM 文件?


  • Maven 读取 pom.xml 文件。
  • 下载项目的依赖到本地仓库。
  • 执行构建的生命周期中,包括构建阶段和构建目标。
  • 执行插件。

POM 文件

当你执行 Maven 命令时,你需要告诉 Maven 根据哪个 POM 文件来执行。

Maven 会对你所指定的 POM 文件中的资源来执行相应的命令。

构建生命周期、构建阶段、构建目标

在 Maven 中,构建阶段被分为 1.构建生命周期、2.构建阶段和3.构建目标。

一个构建生命周期由一系列构建阶段组成,而每一个构建阶段都由一系列构建目标组成。

当你使用 Maven 执行一条命令时,这条命令应是一构建生命周期、构建阶段或构建目标。

如果是执行一个构建生命周期,则该生命周期中所有的构建阶段都会被执行。

如果是执行一个构建阶段,那么在此构建阶段被执行之前,它前面的所有阶段都会被依次执行。

依赖和仓库

Maven 最先执行的构建目标就是检查你项目的所有依赖,依赖就是项目中使用的外部 JAR 文件。

如果依赖在本地仓库中没有找到,那么 Maven 就会从中央从库中进行下载,并把下载下来的依赖放到本地仓库中(当然,你可以通过配置跳过该步骤)。

此外,你也可以指定 Maven 来使用哪个中央仓库进行下载(Maven 默认使用的中央仓库服务器在国外,下载速度较慢,可以换成清华或阿里的中央仓库)。



构建插件

构建插件用来向一个构建阶段添加额外的构建目标。

如果你需要让 Maven 在执行构建阶段时执行一些额外的构建目标,

你可以在 POM 文件中添加一个插件来达到此目的,

Maven 为我们提供了一些标准插件供我们使用,你也可以使用 Java 来编写你自己的插件。


提示:运行 Maven 需要 Java 环境的支持。


构建配置文件

构建配置文件可以让你以多种方式来构建你的项目。

例如,你可能会想要在本地构建你的项目来进行开发和测试,

同时你又可能需要把项目部署到远程的生产环境。

这两种情况下的构建流程很可能是不同的,

为了实现这个目标,

你只需向你的 POM 文件中添加不同的构建配置文件,

并在使用 Maven 执行构建时选择使用与环境对应的配置文件进行构建即可。

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>org.codehaus.mojo</groupId>
<artifactId>my-project</artifactId>
<version>1.0</version>
</project>

以上是一个 POM 文件的最小配置,

groupId:artifactId:version 这三个标签是必需的。

这三个标签结合起来可以实现一个地址和一个时间戳的作用,

它在 Maven 仓库中定义了一个唯一的坐标,

通过这个坐标,我们可以准确的找到 Maven 仓库中的任何 JAR 包。

<project>:
该标签是 POM 文件的根标签,它定义了 POM 文件的命名空间,即其子标签的引用来源。

<groupId>:
代表组织和整个项目的唯一标志。应遵循 Java 包命名规范。如所有 Apache 基金会的 groupId 为 org.apache。

<artifactId>:
代表该项目的全局唯一 Id,即项目的名称。

<version>:
指定项目的版本。

<packaging>:
定义项目以何种方式进行打包,可选值有:pom, jar, maven-plugin, ejb, war, war, ear, rar。

<parent>:
POM 文件是可以继承的,该标签用于指定父 POM 的相关配置。

<properties>:
用于声明一些常量,例如上述代码中的源码编码为 UTF-8,输出代码也为 UTF-8,Java 版本为 1.8。

<dependencies>:
依赖的根元素,里面可以包含多个 dependency 元素,dependency 里具体为各个依赖 Jar 的 3 个坐标,即 groupId、artifactId 和 version。如果缺少 version,Maven 会尝试从父 POM 中获取该依赖的 version。

<modules>:
定义项目的子项目(子模块)。

<dependencyManagement>:
用来管理项目子模块的依赖版本。

<properties>:
Maven properties 是值占位符,在该标签下定义子标签,之后可以在 POM 的任何位置通过 ${} 的形式来引用其子标签的值。

Maven的目录结构

标准的 maven 项目的目录结构

basedir
|-- pom.xml
|-- src
| |-- main
| | `-- java
| | `-- resources
| | `-- filters
| `-- test
| | `-- java
| | `-- resources
| | `-- filters
| `-- it
| `-- assembly
| `-- site
`-- LICENSE.txt
`-- NOTICE.txt
`-- README.txt

目录

描述

src/main/java

项目源代码目录

src/main/resources

项目资源文件目录

src/main/filters

项目资源过滤文件目录

src/main/webapp

Web 应用源代码目录

src/test/java

项目测试代码目录

src/test/resources

项目测试代码资源目录

src/test/filters

项目测试代码资源过滤文件目录

src/it

集成测试代码目录(主要供插件使用)

src/assembly

组件描述符目录

src/site

站点文件目录

LICENSE.txt

项目的许可文件

NOTICE.txt

项目的注意事项文件

README.txt

项目的介绍文件

标准的maven项目目录结构不需要我们自己去创建 ,通过 maven工具进行生成 就可以快速创建出 这种文件结构

Maven 的生命周期

构建生命周期

Maven 有 3 个内置的生命周期,如下。


  1. default
  2. clean
  3. site
    每个构建生命周期关注整个软件项目构建的不同方面。
    因此,每个构建生命周期都被独立执行,不依赖其他生命周期。
    你可以让 Maven 执行多个构建生命周期,但它们会按规定的顺序分别执行。


  • default 生命周期用于处理项目的编译和打包。
  • clean 生命周期用于将临时文件从输出文件夹中清除,包括编译后的源代码,文档以及之前打包的 JAR 文件。
  • site 生命周期用于生成项目的文档文件。实际上,site 可以为项目的文档生成整个网站。

构建阶段

每个构建生命周期都被划分为一系列的构建阶段,每一个构建阶段又被划分为一系列的构建目标。

因此,整个构建流程就是一系列的构建生命周期、构建阶段和构建目标。

你可以执行一整个构建生命周期如(default,clean 或 site),

或者执行一个构建阶段(如 default 生命周期的一个构建阶段 install),

又或者是执行一个构建目标(如 dependency:copy-dependencies)。

default 生命周期是最重要的,因为在这个生命周期中构建了项目的源代码。

由于我们不能直接执行生命周期,因此我们需要执行该生命周期中的一个构建阶段或是构建目标。

default 生命周期有许多的构建阶段和构建目标,这里只列出最常见的几个构建阶段。

构建阶段

描述

validate

检查项目配置是否正确,完成构建的所有必要信息是否能够获取到。同时确认依赖是否已经下载,如果没有,将会进行下载。

compile

编译项目源代码。

test

使用合适的单元测试框架对编译后的代码进行测试。测试不需要源代码已打包或部署。

pakcage

打包编译好的源代码为其可发行的格式,如一个 JAR 文件。

install

安装包到本地的仓库,方便其他项目在本地使用。

deploy

拷贝打包好的程序到远程仓库,供其他开发者和项目共享。

当你执行一个构建阶段时,该构建阶段之前的所有构建阶段都会被从上到下按顺序执行。例如上表,在执行 package 构建阶段时,Maven 首先按顺序执行 validate、compile 和 test 三个构建阶段。

构建目标

构建目标是 Maven 构建项目中的最小单位,一个目标可以和任意个构建阶段绑定。

如果一个目标没有和任何构建阶段绑定,你可以在执行 mvn 命令时传递构建目标名来执行它。

如果一个构建目标和一个或多个构建阶段绑定,那么每次这些构建阶段被执行时它都会被执行。

Maven 项目快速创建

使用「原型(Archetype)」快速 创建 Maven 项目


安装Maven 后在命令行输入

mvn archetype:generate

在控制台中输入 maven-archetype-quickstart 的序号 7(默认为我们选择的就是 7),

然后控制台中会依次让我们填写项目的 groupId、artifactId、version 以及 package,version 和 package 有默认值,不填写并回车就会使用默认值

也可以不使用交互直接配置好 命令

mvn archetype:generate 
-DgroupId=com.hanxu51
-DartifactId=maven-demo
-DarchetypeArtifactId=maven-archetype-quickstart
-DinteractiveMode=false

各个参数代表的含义


  • mvn:使用 Maven 来执行命令。所有 Maven 相关的命令都需要使用 mvn 来执行
  • archetype:generate:使用该 Maven 插件来基于原型创建 Maven 工程
  • DgroupId:定义项目的 groupId。此处为 com.hanxu51
  • DartifactId:定义项目的 artifactId。此处为 maven-demo
  • DarchetypeArtifactId:指定使用的原型。此处为 maven-archetype-quickstart
  • DinteractiveMode:是否开启交互模式。此处为 false,即关闭交互模式。关闭交互模式之后,在命令参数上没有指定的内容,如此处的 version 和 package,都将使用默认值

运行 maven 项目

# 进入 Maven 工程的根目录
cd maven-demo
# 使用 Maven 命令运行程序
mvn clean compile exec:java -Dexec.mainClass=com.hanxu51.App

  • compile:将程序源代码进行编译,并输出到 target 目录下。
  • clean:清理上次编译输出的文件。
  • exec:java:使用该插件来执行我们程序中的主函数(main())。程序只有被编译为 .class 文件之后才能被执行,但不需要每次都对源代码进行编译,一般只在第一次编译程序和对代码进行修改之后才对源代码进行编译。


注:编译时最好使用 mvn clean compile 而不是 mvn compile,多一个 clean 构建阶段可以将之前编译输出的代码清理掉,避免造成此次编译的文件与上一次的文件混乱。


  • Dexec.mainClass:指定 exec:java 执行哪一个 Java 文件的主函数。必须是 Java 文件的全限定类名(全限定类名 = 包名(com.shiyanlou) + “.” + 类名(App)。

对任何 Maven 项目执行命令时,Maven 默认会在执行命令的当前目录下寻找 pom.xml 配置文件来执行。如果没有找到配置文件,Maven 命令将无法正常执行。所以这里我们需要进入到 Maven 工程的根目录(/home/project/maven-demo)。如果当前目录下找不到 pom.xml 文件,执行会报错,

如果不想每次进入到目录再执行 Maven 命令,可以使用 -f 选项来为 Maven 命令指定使用的 pom.xml 文件位置。如 mvn exec:java -Dexec.mainClass=com.hanxu51.App -f /home/project/maven-demo/pom.xml

Maven pom快速配置

  • 【最全最多的中央仓库】mvnrepository https://mvnrepository.com/

中央仓库 搜索 mysql8.0 获得角标

比如加入 mysql8.0 的 依赖 可以直接在 pom.xml 加入这些角标

<!-- https://mvnrepository.com/artifact/mysql/mysql-connector-java -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.18</version>
</dependency>

【重学maven】构建标准清晰地java工程_java_03

首先 mvn clean compile 这条命令作用是先清理程序之前编译的结果,然后将我们 src 目录下的源代码进行编译。

「当你执行一个构建阶段时,该构建阶段之前的所有构建阶段都会被从上到下按顺序执行」,这里 Maven 执行的 compile 构建阶段之前的构建阶段有:



validate,该构建阶段将「检查项目配置是否正确,完成构建的所有必要信息是否能够获取到。
同时确认依赖是否已经下载,如果没有,将会进行下载」。
所以可以肯定,当执行完 mvn compile 之后,项目所依赖的 mysql-connector-java 依赖已经被下载到本地仓库了。



mvn exec:java -Dexec.mainClass=com.hanxu51.App -Dexec.cleanupDaemonThreads=false 命令之前已经介绍过了,它是用来执行程序中的主函数的。这里我们多设置了一个参数



Dexec.cleanupDaemonThreads=false,这是因为在使用 mysql-connector-java 进行数据库连接时,程序中不止有一个线程在运行,还有守护线程在运行,而主函数退出之后,exec 插件开始强制退出这些线程,如果线程没有及时退出,就会报错,这里我们使用 -Dexec.cleanupDaemonThreads=false 来禁止强制退出,避免报错




注意,当我们修改源码之后,在运行代码之前需要重新使用 mvn clean compile 命令编译源代码,否侧 exec:java 还是会运行之前编译的代码。


Maven 自动化单元测试

Maven 做了许多的工作并高度整合 junit 框架来让开发人员能够专注于编写测试代码,而不用关心环境相关的问题。我们只需要在 src/test 目录下创建测试类,编写测试方法,就能够快速对我们的代码进行单元测试。

修改 pom.xml 引入角标

<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>

全局控制版本号

<properties>
<junit.version>4.12</junit.version>
</properties>

<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>${junit.version}</version>
<scope>test</scope>
</dependency>

运行

mvn test -Dtest=com.hanxu51.AppTest#testGetConnection

Maven 打包

mvn clean package

跳过测试

mvn clean package -Dmaven.test.skip=true