乐趣区

关于java:Maven这7个问题你思考过没有

送大家以下 java 学习材料,文末有支付形式

当初的我的项目中 Maven 随处可见,面试的时候,常常会被问一些我的项目中 Maven 的问题,然而平时 Maven 我的项目个别不会出什么问题,可能你不太留神,以下 7 个问题,个别说进去并把握,至多能够证实你 Maven 用的熟练度还能够。

Maven 的仓库治理、依赖治理、继承和聚合等个性为我的项目的构建提供了一整套欠缺的解决方案,如果你搞不懂 Maven,那么一个多模块的我的项目足以让你头疼,依赖抵触就会让你手足无措,甚至搞不清楚我的项目是如何运行起来的 …

OK,博主就已经被 Maven“挫伤”过,所以,咱们要:彻底搞定 Maven!

回忆一下,当你新到一家公司,装置完 JDK 后就会装置配置 Maven,很大可能性你须要批改 settings.xml 文件,比方你会批改本地仓库地址门路,比方你很可能会 copy 一段配置到你的 settings.xml 中(很可能就是私服的一些配置)。接下来,你会到 IDEA 或者 Eclipse 中进行 Maven 插件配置,而后你就能够在工程中的 pom.xml 外面开始增加标签来治理 jar 包,在 Maven 标准的目录构造下进行编写代码,最初你会通过插件的形式来进行测试、打包(jar or war)、部署、运行。

下面形容了对 Maven 的一些应用形式,上面咱们进行一些思考:

1、本地仓库?Maven 到底有哪些仓库?它们什么关系?

Maven 仓库:

本地仓库门路配置:

你要 jar 包,不可能每次都要联网去下载吧,多吃力,所以本地仓库就是相当于加了一层 jar 包缓存,先到这里来查。如果这里查不到,那么就去私服上找,如果私服也找不到,那么去地方仓库去找,找到 jar 后,会把 jar 的信息同步到私服和本地仓库中。

私服 ,就是公司外部局域网的一台服务器而已,你想一下,当你的工程 Project- A 依赖他人的 Project- B 的接口,怎么做呢?没有 Maven 的时候,当然是 copy Project-B jar 到你的本地 lib 中引入,那么 Maven 的形式,很显然须要其他人把 Project-B deploy 到私服仓库中供你应用。 因而私服中存储了本公司的外部专用的 jar!不仅如此,私服还充当了地方仓库的镜像,说白了就是一个代理!

地方仓库:该仓库存储了互联网上的 jar,由 Maven 团队来保护,地址是:http://repo1.maven.org/maven2/。

2、对于 <dependency> 的应用

依赖治理:

img\_0822\_02\_\_4.png

其实这个标签揭示了 jar 的查找坐标:groupIdartifactIdversion

一般而言,咱们能够到私服上输出 artifactId 进行搜寻,或者到 http://search.maven.org/、http://mvnrepository.com/ 上进行查找确定坐标。

version 分为开发版本(Snapshot)和公布版本(Release),那么为什么要分呢?

在理论开发中,咱们常常遇到这样的场景,比方 A 服务依赖于 B 服务,A 和 B 同时开发,B 在开发中发现了 BUG,批改后,将版本由 1.0 降级为 2.0,那么 A 必须也跟着在 POM.XML 中进行版本升级。过了几天后,B 又发现了问题,进行批改后降级版本公布,而后告诉 A 进行降级 … 能够说这是开发过程中的版本不稳固导致了这样的问题。

Maven,曾经替咱们想好了解决方案,就是应用 Snapshot 版本,在开发过程中 B 公布的版本标记为 Snapshot 版本,A 进行依赖的时候抉择 Snapshot 版本,那么每次 B 公布的话,会在私服仓库中,造成带有工夫戳的 Snapshot 版本,而 A 构建的时候会主动下载 B 最新工夫戳的 Snapshot 版本!

3、既然 Maven 进行了依赖治理,为什么还会呈现依赖抵触?解决依赖抵触的伎俩是?

依赖的版本?

首先来说,对于 Maven 而言,同一个 groupId 同一个 artifactId 下,只能应用一个 version

依据上图的依赖程序,将应用 1.2 版本的 jar。

当初,咱们能够思考下了,比方工程中须要引入 A、B,而 A 依赖 1.0 版本的 C,B 依赖 2.0 版本的 C,那么问题来了,C 应用的版本将由引入 A、B 的程序而定?这显然不靠谱!如果 A 的依赖写在 B 的依赖前面,将意味着最初引入的是 1.0 版本的 C,很可能在运行阶段呈现类(ClassNotFoundException)、办法(NoSuchMethodError)找不到的谬误(因为 B 应用的是高版本的 C)!

这里其实波及到了 2 个概念:依赖传递(transitive)、Maven 的最近依赖策略。

依赖传递:如果 A 依赖 B,B 依赖 C,那么引入 A,意味着 B 和 C 都会被引入。

Maven 的最近依赖策略:如果一个我的项目依赖雷同的 groupId、artifactId 的多个版本,那么在依赖树(mvn dependency:tree)中离我的项目最近的那个版本将会被应用。(从这里能够看出 Maven 是不是有点小问题呢?能不能抉择高版本的进行依赖么?据理解,Gradle 就是 version+ 策略)

当初,咱们能够想想如何解决依赖抵触呢?

想法 1:要应用哪个版本,咱们是分明的,那么能不能不论如何依赖传递,都能够进行版本锁定呢?

应用<dependencyManagement> 这种次要用于子模块的版本一致性中

想法 2:在依赖传递中,能不能去掉咱们不想依赖的?

应用 <exclusions> 在理论中咱们能够在 IDEA 中间接利用插件帮忙咱们生成

想法 3:既然是最近依赖策略,那么咱们就间接应用显式依赖指定版本,那不就是最靠近我的项目的么?

应用<dependency>

4、引入依赖的最佳实际,提前发现问题!

在工程中,咱们防止不了须要加一些依赖,兴许加了依赖后运行时才发现存在依赖抵触在去解决,仿佛有点晚!那么能不能提前发现问题呢?

如果咱们新退出一个依赖的话,那么先通过 mvn dependency:tree 命令造成依赖树,看看咱们新退出的依赖,是否存在传递依赖,传递依赖中是否和依赖树中的版本存在抵触,如果存在多个版本抵触,利用上文的形式进行解决!

5、Maven 规范化目录构造

这里须要留神 2 点:

1、src/main 下内容最终会打包到 Jar/War 中,而 src/test 下是测试内容,并不会打包进去。

2、src/main/resources 中的资源文件会 COPY 至目标目录,这是 Maven 的默认生命周期中的一个规定动作。(想一想,hibernate/mybatis 的映射 XML 须要放入 resources 下,而不能在放在其余中央了)

6、Maven 的生命周期

Maven 生命周期:

咱们只须要留神一点:执行前面的命令时,后面的命令主动失去执行。

实际上,咱们最罕用的就是这么几个:

1、clean:有问题,多清理!

2、package:打成 Jar or War 包,会主动进行 clean+compile

3、install:将本地工程 Jar 上传到本地仓库 

4、deploy:上传到私服

7、对于 scope 依赖范畴

既然,Maven 的生命周期存在编译、测试、运行这些过程,那么显然有些依赖只用于测试,比方 junit;有些依赖编译用不到,只有运行的时候能力用到,比方mysql 的驱动包 在编译期就用不到(编译期用的是 JDBC 接口 ),而是在运行时用到的;还有些依赖,编译期要用到,而运行期不须要提供,因为有些容器曾经提供了,比方servlet-api 在 tomcat 中曾经提供了,咱们只须要的是编译期提供而已。

总结来说:

1、compile:默认的 scope,运行期无效,须要打入包中。

2、provided:编译期无效,运行期不须要提供,不会打入包中。

3、runtime:编译不须要,在运行期无效,须要导入包中。(接口与实现拆散)

4、test:测试须要,不会打入包中。

5、system:非本地仓库引入、存在零碎的某个门路下的 jar。(个别不应用)

退出移动版