基本概念

是什么?

Maven是一个强大的Java项目构建工具。

什么是构建工具?

构建工具是将软件项目构建相关的过程自动化的工具。构建一个软件项目通常包含以下一个或多个过程:

  1. 生成源码(如果项目使用自动生成源码);
  2. 从源码生成项目文档;
  3. 编译源码;
  4. 运行单元测试
  5. 将编译后的代码打包成JAR文件或者ZIP文件;
  6. 将打包好的代码安装到服务器、仓库或者其它的地方;
  7. 叙述项目间的依赖关系

有些项目可能需要更多的过程才能完成构建,这些过程一般也可以整合到构建工具中,因此它们也可以实现自动化。

自动化构建过程的好处是将手动构建过程中犯错的风险降到最低。而且,自动构建工具通常要比手动执行同样的构建过程要快。

核心概念:POM文件(POM project object mode项目对象模型)

POM文件是以XML文件的形式表述项目的资源,如源码、测试代码、依赖(用到的外部Jar包)等。

pom主要组成部分:

简单运行

当你安装好了Maven,并且在项目的根目录下创建了POM文件,可以在项目上运行Maven了。

mvn clean install

该命令首先执行clean构建周期,删除Maven输出目录中已编译的类文件,然后执行install构建阶段。

maven深入实践

构建生命周期

Maven中内置了三个构建生命周期:default,clean和site。default生命周期处理工程的部署,clean生命周期处理工程的清理,而site生命周期则负责创建工程的站点文档。

packaging直接影响Maven的构建生命周期。

在Maven 3中,其可用的打包类型如下:

  1. jar,默认类型
  2. war
  3. ejb
  4. ear
  5. rar
  6. par
  7. pom
  8. maven-plugin

如果想一次打包多个项目,可采用聚合类型pom,它通常由一个父模块和若干个子模块构成。

<packaging>pom</packaging>

<modules>
<module>zy-service-consumer</module>
<module>zy-eureka-server</module>
<module>zy-zipkin-service</module>
<module>zy-hystrix-dashboard</module>
</modules>

构建生命周期是由阶段组成的

三个构建生命周期都是由一系列不同的构建阶段组成,每一个构建阶段代表了生命周期的一个阶段。

以default生命周期为例,它是由以下的阶段组成

  • validate – 验证该项目是否正确,所有必要的信息都是可用的
  • compile – 编译工程源码
  • test – 使用一个合适的单元测试框架测试编译的源代码。这些测试的代码不会被打包或部署到项目中
  • package – 将编译的代码打包成它发布的格式,例如JAR
  • integration-test – 如果必要的话,该命令会将工程处理并部署在一个集成测试运行的环境中
  • verify – 运行任何检查以验证该包是否有效,是否符合质量标准
  • install – 将工程打包安装到本地仓库中,以便本地其他项目可以进行依赖
  • deploy – 在集成或发布环境中,将最终工程打包复制到远程仓库中,用于与其他开发人员和项目共享
mvn deploy
它不仅执行指定的构建阶段,而且会执行指定构建阶段之前的每一个阶段。因此,执行

构建阶段使用的构建插件

mvn install

[INFO] ------------------------------------------------------------------------
[INFO] Building zy-zeromq 1.0.0
[INFO] ------------------------------------------------------------------------
[INFO]
[INFO] --- maven-resources-plugin:2.6:resources (default-resources) @ zy-zeromq ---
[INFO]
[INFO] --- maven-compiler-plugin:3.1:compile (default-compile) @ zy-zeromq ---
[INFO]
[INFO] --- maven-resources-plugin:2.6:testResources (default-testResources) @ zy-zeromq ---
[INFO]
[INFO] --- maven-compiler-plugin:3.1:testCompile (default-testCompile) @ zy-zeromq ---
[INFO]
[INFO] --- maven-surefire-plugin:2.18.1:test (default-test) @ zy-zeromq ---
[INFO]
[INFO] --- maven-jar-plugin:2.6:jar (default-jar) @ zy-zeromq ---
[INFO]
[INFO] --- maven-install-plugin:2.5.2:install (default-install) @ zy-zeromq ---

(查看完整的生命周期阶段列表,请参考生命周期参考

仓库

仓库只分为两类:本地仓库和远程仓库。

当Maven根据坐标寻找构建的时候,首先会查看本地仓库,如果本地仓库存在此构件,则直接使用;如果本地仓库不存在此构件,或者需要查看是否有更新的构件版本,Maven就会到远程仓库查找,发现需要的构件后,将其下载到本地仓库再使用。如果本地仓库和远程仓库都不存在需要的构件,则报错。

私服

私服的好处:节约外网的带宽,加速Maven的构建,方便部署第三方构件,稳定等

部署到远程仓库

将本项目jar包上传到私服、远程仓库,供项目组或其他人使用。配置如下:

pom.xml
<distributionManagement>
<repository>
<id>thirdparty</id>
<name>3rd party</name>
<url>http://192.168.100.103:8081/nexus/content/repositories/thirdparty/</url>
</repository>
</distributionManagement> settigns.xml配置认证
<servers>
<server>
<id>thirdparty</id>
<username>repo-user</username>
<password>repo-psw</password>
</server>
</servers> mvn命令:
本地仓库 的更新
mvn clean package install
远程 仓库 的更新
mvn clean package deploy 如果编译出问题时,可以执行如下命令
mvn clean install -e -U
-e详细异常,-U强制更新

为了加速下载,可以配置一些镜像mirror。

依赖

依赖传递性

  1. 子项目可以继承父项目的依赖
  2. 项目A依赖项目B,项目A-->项目B,项目B中的依赖也会被加入到项目A中。

由于依赖的传递性,导致项目中存在多个同名的jar包,存在jar包冲突等。maven提供的以下机制来解决这些问题:

依赖调解原则

过从Maven 2.0.9开始,POM中依赖声明的顺序决定了哪个版本会被使用,也叫作”第一声明原则”。

依赖管理

在多模块应用中,可能多个子项目会有共同的依赖。

在顶层的pom中指定依赖项的版本,以便让所有的子项目使用同一版本。dependency management只是依赖的一个声明,子项目需显式引用,但不用指定版本号。

父项目pom
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>${spring-cloud.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement> 子项目pom,需显式引用依赖,但不用指定版本号。
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-eureka</artifactId>
</dependency>

依赖范围

  • compile 默认的scope,表示 dependency 都可以在生命周期中使用。而且,这些dependencies 会传递到依赖的项目中。适用于所有阶段,会随着项目一起发布
  • provided 跟compile相似,但是表明了dependency 由JDK或者容器提供,例如Servlet AP和一些Java EE APIs。这个scope 只能作用在编译和测试时,同时没有传递性。
<dependency>
<groupId>org.apache.storm</groupId>
<artifactId>storm-core</artifactId>
<version>1.1.1</version>
<scope>provided</scope>
</dependency>
  • runtime 表示dependency不作用在编译时,但会作用在运行和测试时,如JDBC驱动,适用运行和测试阶段。
  • system 跟provided 相似,但是在系统中要以外部JAR包的形式提供,maven不会在repository查找它。
  • import(Maven2.0.9及以上)

    import范围只适用于pom文件中的部分。表明指定的POM必须使用部分的依赖。因为依赖已经被替换,所以使用import范围的依赖并不影响依赖传递。
  • test 范围表明使用此依赖范围的依赖,只在编译测试代码和运行测试的时候需要,应用的正常运行不需要此类依赖。

依赖排除

<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jdbc</artifactId>
<exclusions>
<exclusion>
<groupId>org.apache.tomcat</groupId>
<artifactId>tomcat-jdbc</artifactId>
</exclusion>
</exclusions>
</dependency>
  • 小技巧:一般在编译时类找不到,但是实际存在jar冲突情况时。在idea中安装Maven Helper插件,根据jar名称搜索,定位到具体的依赖,在依赖中排除冲突jar包。

可选依赖

可选的依赖工作原理

Project-A -> Project-B

上面的图意味着项目A依赖于项目B,当A在它的POM文件中把B声明为一个可选的依赖,他们的关系依然没有改变。仅仅就像一次正常的构建,在这次构建中,项目B将会被添加进classpath。

Project-X -> Project-A

但是当一个其他的项目(项目X)在它的POM文件中声明项目A为一个依赖,这个可选的依赖就发挥作用了。你将会注意到项目X的classpath不会包含项目B:为了把B包含进项目X的classpath,你需要在你的POM文件中直接声明。

例子:

有一个名为X2的项目,这个项目和hibernate有一些类似的功能,支持许多数据库驱动/依赖,比如说MySQL,postgre,oracle等。为了构建X2,所有的这些依赖都是必须的,但是对于你的项目来说却不是必须的,所以对于X2把这些依赖声明为可选的是非常实用的,不论什么时候当你在POM文件中把X2声明为一个直接依赖的时候,所有被X2支持的驱动不会自动的被包含进你的项目的classpath,你需要直接声明你将要使用的数据库的依赖/驱动。

自定义打包maven-assembly-plugin

在运行mapreduce/storm时,一般是以jar包方式运行,每个jar包中依赖的jar的包,可以采用maven-assembly-plugin。

<build>
<plugins>
<plugin>
<artifactId>maven-assembly-plugin</artifactId>
<configuration>
<appendAssemblyId>false</appendAssemblyId>
<descriptors>
<descriptor>assembly.xml</descriptor>
</descriptors>
<finalName>${project.artifactId}-${project.version}</finalName>
<attach>false</attach>
</configuration>
<executions>
<execution>
<id>make-assembly</id>
<phase>package</phase><!-- 绑定到package生命周期阶段上 -->
<goals>
<goal>single</goal><!-- 只运行一次 -->
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>

assembly.xml

<!--是否生成和项目名相同的根目录-->
<includeBaseDirectory>false</includeBaseDirectory>
<fileSets>
<fileSet>
<directory>${project.basedir}/target/classes</directory>
<outputDirectory>.</outputDirectory>
</fileSet>
<!--<fileSet>
<directory>${project.basedir}/src/main/resources</directory>
<outputDirectory>./</outputDirectory>
</fileSet>-->
</fileSets>
<dependencySets>
<dependencySet>
<!--是否把本项目添加到依赖文件夹下-->
<useProjectArtifact>false</useProjectArtifact>
<outputDirectory>/lib</outputDirectory>
<!--<excludes>
<exclude>org.apache.storm:storm-core</exclude>
</excludes>-->
</dependencySet>
</dependencySets>

其他常见配置方法

<configuration>
<descriptorRefs>
<descriptorRef>jar-with-dependencies</descriptorRef>
</descriptorRefs>
...
</configuration>
这种方式打出的包是fat jar,也就是把依赖的jar包全部解压成class文件后,再与自己的代码打成一个jar包。

maven assembly

命令

  1. mvn clean 清除目标目录中的生成结果
  2. mvn package 依据项目生成 jar 文件,打包之前会进行编译,测试
  3. mvn install在本地 Repository 中安装 jar
跳过测试类 : -Dmaven.test.skip=true
下载jar包源码: -DdownloadSource=true
下载javadocs: -DdownloadJavadocs=true

Archrtype

原型(Archetype)是一个Maven工程模板工具包。

maven-archetype-quickstart用得比较多。

maven vs gradle

  • maven和gradle的比较与使用

    总的来说,gradle相比于maven有很打的灵活性,目前gradle的使用者越来越多。而由于maven之前处于主流,并且在某些方面maven较gradle还有一些优点,所以maven和gradle并存。在github上大多数优秀的开源项目会同时提供maven和gradle两种添加依赖的方式。

参考文献


tips:本文属于自己学习和实践过程的记录,很多图和文字都粘贴自网上文章,没有注明引用请包涵!如有任何问题请留言或邮件通知,我会及时回复。

maven实践--你所需要了解的maven的更多相关文章

  1. 学习笔记——Maven实战(四)基于Maven的持续集成实践

    Martin的<持续集成> 相信很多读者和我一样,最早接触到持续集成的概念是来自Martin的著名文章<持续集成>,该文最早发布于2000年9月,之后在2006年进行了一次修订 ...

  2. Maven实战(四)——基于Maven的持续集成实践

    Martin的<持续集成> 相信非常多读者和我一样.最早接触到持续集成的概念是来自Martin的著名文章<持续集成>.该文最早公布于2000年9月,之后在2006年进行了一次修 ...

  3. maven 实践 :管理依赖

    有人认为Maven是一个依赖管理工具,当然这种想法是错误的(确切的说Maven是一个项目管理工具,贯穿了整个项目生命周期,编译,测试,打包,发布...),但Maven给人造成这种错误的印象也是有原因的 ...

  4. 学习笔记——Maven实战(七)常用Maven插件介绍(上)

    我们都知道Maven本质上是一个插件框架,它的核心并不执行任何具体的构建任务,所有这些任务都交给插件来完成,例如编译源代码是由maven-compiler-plugin完成的.进一步说,每个任务对应了 ...

  5. 学习笔记——Maven实战(八)常用Maven插件介绍(下)

    我们都知道Maven本质上是一个插件框架,它的核心并不执行任何具体的构建任务,所有这些任务都交给插件来完成,例如编译源代码是由maven- compiler-plugin完成的.进一步说,每个任务对应 ...

  6. Maven使用笔记(七)Maven使用问题记录

    1.Java-maven异常-cannot be cast to javax.servlet.Filter 报错 tomcat 启动后先将tomcat/lib目录下的jar包全部读入内存,如果weba ...

  7. Maven学习总结(28)——Maven+Nexus+Myeclipse集成

    Maven简介 Maven 是一个基于项目对象模型(POM)的,提倡约定优于配置(ConventionOver Configuration)的,跨平台的项目管理和构建自动化工具. 首先它是一个优秀的构 ...

  8. Maven学习总结(14)——Maven 多模块项目如何分工?

    一.开场白 使用Maven有段时间了,只能感慨真是个好东西,让我从传统模式体会到了严谨.规范.敏捷.方便的特性. 如果你懂Maven或许看过Juven翻译的<Maven权威指南>: 发个牢 ...

  9. Maven项目构建利器02——安装Maven核心程序

    1.Maven也是用Java编写的工具,同样运行在JVM上,所以我们在安装Maven之前需要确保已经安装了JDK,首先来检查电脑上是否安装JDK. 2.如上图说明电脑中已经安装了JDK,下面就要去官网 ...

随机推荐

  1. Apollo分布式部署总结

    环境 操作系统为centOS7 Apollo服务端为Java版本为1.8 MySQL5.8.x 环境DEV 注意事项 按文档安装config与admin的数据库,并修改相关配置 在修改Apollo P ...

  2. 详解mysql复制机制--异步复制,半同步复制和并行复制

    图4 那么如何并行化,并行IO线程,还是并行SQL线程?其实两方面都可以并行,但是并行SQL线程的收益更大,因为SQL线程做的事情更多(解析,执行).并行IO线程,可以将从Master拉取和写Rela ...

  3. Synchronized与Lock的区别与应用场景

    转载. https://blog.csdn.net/fly910905/article/details/79765381 同步代码块,同步方法,或者是用java提供的锁机制,我们可以实现对共享资源变量 ...

  4. git安装配置相关

    Git是一个分布式的版本控制系统,最初由Linus Torvalds编写,用作Linux内核代码的管理.在推出后,Git在其它项目中也取得了很大成功,尤其是在Ruby社区中.目前,包括Rubinius ...

  5. luogu P3959(2017noipTG D2T2

    luogu P3959(2017noipTG D2T2 不知道为什么,这两天见了好多伪装成图的dp题,这道也是. 最短路只有40分,实际上可以从数据范围n<=12看出来是状压dp. soluti ...

  6. java的Thread Dump诊断工具

    1.1什么是Thread Dump? Thread Dump是非常有用的诊断Java应用问题的工具.每一个Java虚拟机都有及时生成所有线程在某一点状态的thread-dump的能力,虽然各个 Jav ...

  7. 怎样获取NodeList某位置上的节点

    1. 使用类似 Array 的中括号写法: document.body.childNodes[0] 2. 使用 NodeList.prototype.item(): document.body.chi ...

  8. Fullscreen API:全屏操作

    function launchFullscreen(element) { if(element.requestFullscreen) { element.requestFullscreen(); } ...

  9. B-Tree和 B+Tree的数据存储结构

    B+树索引是B+树在数据库中的一种实现,是最常见也是数据库中使用最为频繁的一种索引.B+树中的B代表平衡(balance),而不是二叉(binary),因为B+树是从最早的平衡二叉树演化而来的.在讲B ...

  10. (二)创建基于maven的javaFX项目

    首先使用IDEA创建一个javaFX项目 点击finish,这就创建完成了JavaFX项目,只有将其转换为maven项目即可,如图: