欢迎光临
我们一直在努力

java【maven】面试题

六、对比其它构建工具

我们都知道,写完代码之后需要进行编译和运行,以笔者自身为例,使用 IDE 写完代码,需要进行编译,再生成war 包,以便部署到 Tomcat。

在编写 Java 代码的时候,我们除了需要调用 JDK 的 API ,还需要调用许多第三方的 API ,加入没有构建工具,你需要把这些 jar 包下载到本地,然后添加进入工程,在 IDE 中进行添加设置。这种方式非常繁琐,并且在遇到版本升级,Git 同步等时候,程序会变得非常脆弱,极易产生未知错误。所以便有了构建工具的产生,它可以让我们专注于写代码,而不需要考虑如何导入 jar 包,如何升级 jar 包版本,以及 git 多人协作等等问题。这是在编译过程中的优势,在运行和发布的过程中,构建工具依然可以帮助我们将工程生成指定格式的文件。Java 世界中主要有三大构建工具:Ant、maven和Gradle。经过几年的发展,Ant 几乎销声匿迹,Maven 也日薄西

山,而 Gradle 的发展则如日中天。

七、Maven坐标的含义?

<!-- FROM https://github.com/junit-team/junit4/blob/master/pom.xml --> 
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.13-BETA</version>

Maven 给我们制定了一套规则 —— 使用坐标进行唯一标识。Maven 的坐标元素包括 groupId、artifactId、version、packaging、classfifier 。

只要我们提供正确的坐标元素,Maven 就能找到对应的构件,首先去你的本地仓库查找,没有的话再去远程仓库下载。如果没有配置远程仓库,会默认从中央仓库地址(http://repo1.maven.org/maven2)下载构件,该中央仓库包含了世界上大部分流行的开源项目构件,但不一定所有构件都有。

在我们自己开发项目的时候,也是要给我们的项目定义坐标的,这是强制性要求,只有这样,其他项目才能引用该项目的构件。

  • groupId:定义当前 Maven 项目隶属的实际项目。
    • 首先,Maven 项目和实际项目不一定是一对一的关系。比如 Spring FrameWork 这一实际项目,其对应的 Maven 项目会有很多,如 spring-core 、 spring-context 等。这是由于 Maven 中模块的概念,因此,一个实际项目往往会被划分成很多模块。
    • 其次,groupId 不应该对应项目隶属的组织或公司。原因很简单,一个组织下会有很多实际项目,如果groupId 只定义到组织级别,而后面我们会看到,artifactId 只能定义 Maven 项目(模块),那么实际项目这个层次将难以定义。
    • 最后,groupId 的表示方式与 Java 包名的表达方式类似,通常与域名反向一一对应。
    • 上例中,groupId 为 junit ,是不是感觉很特殊,这样也是可以的,因为全世界就这么个 junit ,它也没有很多分支。
  • artifactId:该元素定义当前实际项目中的一个 Maven 项目(模块)。
    • 推荐的做法是使用实际项目名称作为 artifactId 的前缀。比如上例中的 junit ,junit 就是实际的项目名称,方便而且直观。
    • 在默认情况下,Maven 生成的构件,会以 artifactId 作为文件头。例如 junit-3.8.1.jar ,使用实际项目名称作为前缀,就能方便的从本地仓库找到某个项目的构件。
  • version:该元素定义了使用构件的版本。
    • 如上例中 junit 的版本是 4.13-BETA ,你也可以改为 4.1.2 表示使用 4.1.2 版本的 junit 。
  • packaging:定义 Maven 项目打包的方式,使用构件的什么包。打包方式通常与所生成构件的文件扩展名对应。
    • 如上例中没有 packaging ,则默认为 jar 包,最终的文件名为 junit-4.13-BETA.jar 。
    • 当然,也可以打包成 war 等。
  • classififier:该元素用来帮助定义构建输出的一些附件。附属构件与主构件对应。
    • 如上例中的主构件为 junit-4.13-BETA.jar ,该项目可能还会通过一些插件生成如 junit-4.13- BETA-javadoc.jar 、 junit-4.13-BETA-sources.jar ,这样附属构件也就拥有了自己唯一的坐标。

上述 5 个元素中:

  • groupId 、 artifactId 、 version 是必须定义的。
  • packaging 是可选的(默认为 jar )。 
  • 而 classfier 是不能直接定义的,需要结合插件使用。

 Maven 版本规则?

Maven 主要是这样定义版本规则的: <主版本>.<次版本>.<增量版本> 。比如说 1.2.3 ,主版本是 1 ,次版本是

2 ,增量版本是 3 。

  • 主版本,一般来说代表了项目的重大的架构变更,比如说 Maven 1 和 Maven 2 ,在架构上已经两样了,将来的 Maven 3 和 Maven 2 也会有很大的变化。
  • 次版本,一般代表了一些功能的增加或变化,但没有架构的变化,比如说Nexus 1.3 较之于 Nexus 1.2 来说,增加了一系列新的或者改进的功能(仓库镜像支持,改进的仓库管理界面等等),但从大的架构上来说,1.3和 1.2 没什么区别。增量版本,一般是一些小的 bug fifix ,不会有重大的功能变化。一般来说,在我们发布一次重要的版本之后,随之会开发新的版本。比如说, myapp-1.1 发布之后,就着手开发myapp-1.2 了。由于 myapp-1.2 有新的主要功能的添加和变化,在发布测试前,它会变得不稳定,而 myapp- 1.1 是一个比较稳定的版本,现在的问题是,我们在 myapp-1.1中 发现了一些 BUG(当然在 1.2 中也存在),为了能够在一段时间内修复 BUG 并仍然发布稳定的版本,我们就会用到分支(branch),我们基于 1.1 开启一个分支1.1.1 ,在这个分支中修复 BUG ,并快速发布。这既保证了版本的稳定,也能够使bug得到快速修复,也不同停止1.2 的开发。只是,每次修复分支 1.1.1 中的 BUG 后,需要 merge 代码到 1.2 中。

 多模块如何聚合?

配置一个打包类型为 pom 的聚合模块,然后在该 pom 中使用元素声明要聚合的模块。具体的,参见 《Maven系

列五:多模块项目中的聚合和继承》 文章。

八、Maven <dependencie /> 是什么?

<dependencie /> ,依赖关系。属性如下:

  • groupId :依赖项的 groupId 。 
  • artifactId :依赖项的 artifactId 。 
  • version :依赖项的 version 。 
  • scope :依赖项的适用范围。
compile :默认值,适用于所有阶段(开发、测试、部署、运行),本 jar 会一直存在所有阶 段。 provided :只在开发、测试阶段使用,目的是不让 Servlet 容器和你本地仓库的 jar 包冲突 。 如 servlet.jar 。 runtime :只在运行时使用,如 JDBC 驱动,适用运行和测试阶段。 test :只在测试时使用,用于编译和运行测试代码,不会随项目发布。 system :类似 provided ,需要显式提供包含依赖的 jar 包,Maven 不会在 Repository 中查 找它。 import :用于一个 <dependencyManagement /> 对另一个 <dependencyManagement /> 的 继承。非常重要,通过它,可以实现类似 《Maven Spring BOM (bill of materials)》 的功能。

  • exclusions :排除项目中的依赖冲突时使用。

和<dependencyManagement /> 区别是什么?

  • <dependencyManagement /> , 统一了 Maven 中依赖的版本号,定义在 dependencie /> 中的依赖,在不指定具体版本号时,就会沿着上层找到 <dependencyManagement /> 中的依赖,并使用它的版本号。这样的话,当有多个子项目引用同一个依赖时,就不需要重复声明各自的版本号,只需统一使用<dependencyManagement /> 中的版本号即可。
  • 还有个不同点, <dependencyManagement /> 中出现的依赖,并不一定会在项目中使用,而<dependencie /> 中的依赖,肯定是包含在项目中的。

对于一个多模块项目,如果管理项目依赖的版本?

  • 方式一,通过在父模块中声明 <dependencyManagement /> 和 <pluginManagement /> , 然后让子模块通过元素指定父模块,这样子模块在定义依赖是就可以只定义 groupId 和 artifactId ,自动使用父模块的 version ,这样统一整个项目的依赖的版本。
继承的方式。

  • 方式二,使用 <dependencie /> 声明 <scope /> 为 import 的依赖,从而引入一个 pom 的 <dependencyManagement /> 的。具体的,可以看看 《Maven Spring BOM (bill of materials)》 文章。
组合的方式。

九、Maven 依赖的解析机制是怎么样的?

1. 解析发布(RELEASE)版本:如果本地有,直接使用本地的,没有就向远程仓库请求。

2. 解析快照(SNAPSHOT)版本:合并本地和远程仓库的元数据文件 groupId/artifactId/version/maven- metadata.xml ,这个文件存的版本都是带时间戳的,将最新的一个改名为不带时间戳的格式供本次编译使用。

3. 解析版本为 LATEST 过于复杂,且解析的结果不稳定,不推荐在项目中使用,感兴趣的同学自己去研究,简而言之就是合并 groupId/artifactId/maven-metadata.xml 找到对应的最新版本和包含快照的最新版本。

 

LASTEST、RELEASE、SNAPSHOT 的区别?

 

LASTEST :是指某个特定构件最新的发布版或者快照版(SNAPSHOT),最近被部署到某个特定仓库的构件。

RELEASE :是指仓库中最后的一个非快照版本。

SNAPSHOT :泛指。如果不 SNAPSHOT ,如果名字不变,本地有了不会从远程拉。如果每次更新都改名字,其他用的人也都改名字,太蛋疼了。

Maven 依赖原则?

  • 1、赖路径最短优先原则。
一个项目 Demo 依赖了两个 jar 包,其中 A-B-C-X(1.0) , A-D-X(2.0) 。由于 X(2.0) 路径最短,所以项目使用的是 X(2.0) 。

  • 2、pom文 件中申明顺序优先。
如果 A-B-X(1.0) , A-C-X(2.0) 这样的路径长度一样怎么办呢?这样的情况下,Maven 会根据 pom文件声明的顺序加载,如果先声明了 B ,后声明了 C ,那就最后的依赖就会是 X(1.0) 。

  • 3、覆写优先
子 pom 内声明的优先于父 pom 中的依赖。

如何解决 jar 冲突?

 

遇到冲突的时候第一步,要找到 Maven 加载的到时是什么版本的 jar 包,通过们 mvn dependency:tree 查看依赖树,或者使用 IDEA Maven Helper 插件。

然后,通过 Maven 的依赖原则来调整坐标在 pom 文件的申明顺序是最好的办法,或者使用将冲突中不想要的 jar引入的 jar 进行 <exclusions> 掉。

十、Maven 生命周期是怎么样的?

Maven 中有三个独立的生命周期:

  • 1、Clean
  • 2、Default
  • 3、Site
每个生命周期都有这个特点:不管用户要求执行的命令对应生命周期中的哪一个阶段,Maven都会自动从当前生命周期的最初位置开始执行,直到完成用户下达的指令

一个完整的项目构建过程通常包括清理、编译、测试、打包、集成测试、验证、部署等步骤,Maven 从中抽取了一套完善的、易扩展的生命周期。Maven 的生命周期是抽象的,其中的具体任务都交由插件来完成。Maven 为大多数构建任务编写并绑定了默认的插件,如针对编译的插件: maven-compiler-plugin 。用户也可自行配置或编写插件。

Maven有三套相互独立的生命周期,分别是 Clean、Default 和 Site。每个生命周期包含一些阶段,阶段是有顺序的,后面的阶段依赖于前面的阶段。

  • 1、Clean 生命周期:清理项目,包含三个 phase :
    • pre-clean:执行清理前需要完成的工作。
    • clean:清理上一次构建生成的文件。
    • post-clean:执行清理后需要完成的工作
  • 2、Default 生命周期:构建项目,重要的 phase 如下:
    • validate:验证工程是否正确,所有需要的资源是否可用。
    • compile:编译项目的源代码。
    • test:使用合适的单元测试框架来测试已编译的源代码。这些测试不需要已打包和布署。
    • package:把已编译的代码打包成可发布的格式,比如 jar、war 等。
    • integration-test:如有需要,将包处理和发布到一个能够进行集成测试的环境。
    • verify:运行所有检查,验证包是否有效且达到质量标准。
    • install:把包安装到maven本地仓库,可以被其他工程作为依赖来使用。
    • deploy:在集成或者发布环境下执行,将最终版本的包拷贝到远程的repository,使得其他的开发者或者工程可以共享。
  • 3、Site 生命周期:建立和发布项目站点,phase 如下:
    • pre-site:生成项目站点之前需要完成的工作
    • site:生成项目站点文档
    • post-site:生成项目站点之后需要完成的工作
    • site-deploy:将项目站点发布到服务器

各个生命周期相互独立,一个生命周期的阶段前后依赖。

  • mvn clean :调用 Clean 生命周期的 clean 阶段,实际执行 pre-clean 和 clean 阶段
  • mvn test :调用 Default 生命周期的 test 阶段,实际执行 test 以及之前所有阶段
  • mvn clean install :调用 Clean 生命周期的 clean 阶段和 Default 生命周期 的 install 阶段,实际执行

pre-clean 和 clean ,install 以及之前所有阶段。

而我们在 IDEA Maven 中,也可以看到 Maven 生命周期的操作:

 

  • 海报
海报图正在生成中...
赞(0) 打赏
声明:
1、本博客不从事任何主机及服务器租赁业务,不参与任何交易,也绝非中介。博客内容仅记录博主个人感兴趣的服务器测评结果及一些服务器相关的优惠活动,信息均摘自网络或来自服务商主动提供;所以对本博客提及的内容不作直接、间接、法定、约定的保证,博客内容也不具备任何参考价值及引导作用,访问者需自行甄别。
2、访问本博客请务必遵守有关互联网的相关法律、规定与规则;不能利用本博客所提及的内容从事任何违法、违规操作;否则造成的一切后果由访问者自行承担。
3、未成年人及不能独立承担法律责任的个人及群体请勿访问本博客。
4、一旦您访问本博客,即表示您已经知晓并接受了以上声明通告。
文章名称:《java【maven】面试题》
文章链接:https://www.456zj.com/38623.html
本站资源仅供个人学习交流,请于下载后24小时内删除,不允许用于商业用途,否则法律问题自行承担。

评论 抢沙发

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址