大家好, 这里是K字的研究. 我是最近比较忙的老K.
好久没更新了, 因为最近工作比较紧. 今天礼拜五, 抽空更一篇,表示我还没弃坑. 谈谈maven.说一些我踩过坑才了解到的事.
1起因
想谈这个, 主要是因为工作中实在是发现太多人不懂maven到底怎么用的.这里不提底层原理和插件, 只谈基本的使用, 我们逐个说一下几个基本maven的使用问题.
2maven的基本工作方式
-
天上有个仓库 -
地上( 电脑
)有个仓库 -
仓库的主要内容是 dependency
-
项目有个配方( pom.xml
),里面描述了dependency
-
项目根据配方把 dependency
从天上拉到地上.
正常的使用, 知道这些就可以开始了.基本上的问题都是围绕这些点开展的.
3maven 依赖snapshot版本拉不到
这是一个常见问题, 经常会遇到别人deploy
了以后, 这边拉不到的问题.deploy操作, 只表示了对方把依赖
发到了天上,地上是没有的.
-
形如
0.0.1
这样的版本是普通版 -
形如
0.0.1-snapshot
这样的版本号, 表示这个依赖是快照
版本.
快照版本的更新规则
对于快照版本的管理, maven检查更新的默认周期是1天
. 如果想让maven直接去检查天上是否有更新, 需要加上 mvn -U
来表示, 需要直接去检查天上的新版本.
强制更新命令行参数 -U
如果不添加这个命令行参数-U
那么就会遇到死活拉不到新依赖,下班走人,第二天, 发现好了的灵异事件.
Intellij Idea 强制更新
日常使用的开发工具, 也有设置来表示每次刷新都检查是否是新版.位置在: Build->Build Tools->Maven: Always update snapshots(始终更新快照)

settings.xml内的设置
当然,更新设置的默认设置也可以在settings
里面改动. 在设置里
<snapshotPolicy>always</snapshotPolicy>
这个晚点提到settings
再说.
4maven的依赖(dependency)包含什么
最直觉的想法, 肯定是依赖==jar
,但是其实不全是:
依赖=jar+pom
比如, 我们最常用的spring-boot-starter
, 引入的时候, 可能是这么写的.
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
<version>2.5.5</version>
</dependency>
按照这个描述, 翻开天上的仓库, 会发现, 其实有多份文件. 最核心的是这两份.

这个很重要.
我们引入别人的jar包, 排除依赖等等操作,往往就是在排除随jar
附赠的pom
里面的垃圾内容.
dubbo之类项目的jar包api,打的合不合格, pom里面到底有啥, 就是一个很关键的参考点.
我层有幸见过一个往jar包里带了个springboot-starter-web
的, 我们项目本来是没使用web的,结果因为他的包自动监听了一个8080端口,说多了都是泪.
天上的仓库有哪些
一般来说, maven有个独一无二的大仓库, 人称中央仓库. 地址是Maven Repository: Search/Browse/Explore (mvnrepository.com). maven工具的默认配置就是这个.
但是, 天有二日. 自己也可以使用nexus之类工具, 自行部署天上的仓库. 比如为了方便国内用户快速访问中央仓库, 大企业都提供了免费的镜像加速.常见的比如:
-
阿里镜像 仓库服务 (aliyun.com) -
华为镜像 华为开源镜像站_软件开发服务_华为云 (huaweicloud.com)
当然,因为私有jar包的问题, 很多公司,会自己部署一个镜像在内网. 大多也是使用 nexus 工具.
5地上的仓库在哪里
maven下载下来的依赖, 其实都存在了本地.
默认位置是, 用户主目录( 就是和用户名一样的那个目录)下.m2/repository
文件夹.
-
Linux用户 对应 cd ~/.m2/repository
-
windows用户, WinKey+R
,打开运行, 输入cmd
,跳出来的窗口一般就定位在主目录. 继续cd .m2/repository
即可.
可以改, 但是一般不推荐修改, 没必要.
6设置settings.xml
怎么修改
这个随个人喜好. 但是, 我一般不推荐修改maven
安装文件夹下面的settings.xml
.有需要修改的话, 最好修改主目录下面的settings.xml
.
maven读取配置属性是符合继承关系的.
-
先读取 .m2
下面的settings.xml
里的内容 -
后读取 安装目录
下面的settings.xml
前面说的几个天上仓库, 最好用的是华为的. 因为别的只教你, 加上这个xml片段到settings设置. 但是华为提供了一个完整的settings.xml
.

当然, 别听他后半句修改conf, 直接放到主目录下.m2
就可以. 从命令行进入.m2
的方法是:explorer .
7maven进程杀掉以后, 某个依赖再也拉不到
这个和前面的快照问题还不太一样. 从天上往地上同步时候, 一般maven会选择加一个锁来控制这件事. 这里用的是文件锁, 是一个本地文件,就在本地仓库那个依赖旁边. 如果直接杀死进程, 可能会造成锁文件残留,有时候需要手动清理.
8文件完整性校验
有时候会见到这种形式, sha1结尾的文件.
zookeeper-3.4.9.pom
zookeeper-3.4.9.pom.sha1
其实这里面啥都没有, 就是个校验和9a86b9975bfb98cb82c74a9e45c92e183a526bf2.有些时候可以手动修改pom文件,并修改这个值来避开某些坑, 但是希望你永远用不到这个技能吧. 真心的.
9如何进行扩展
想玩儿一点点花的, 可以参考下以前写过的代码生成
.
10小结
这篇的正文就到这里, 一般性的使用基础,了解上面的就差不多了. 接下来说一点点稍微有点复杂的东西.
11依赖管理
先瞎说几个概念.
pom是什么?
pom全名(project object model), 项目对象模型.
我们前面说settings
就提到过, settings这样的xml是有继承关系的. pom这样的,其实也有. 你看他名字里带个object
,其实就更明显了.
pom继承关系
pom的o是 object, 这里其实和Java的继承是一样的,只是用了xml
来写.
Java对象不指定 extends时候, 父类都是Object
. pom不写父pom, 默认是继承 super POM
.就是这货 Maven Model Builder – Super POM (apache.org) 这个就是所有pom的公共父类.
pom手动指定父pom
<project>
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>com.mycompany.app</groupId>
<artifactId>my-app</artifactId>
<version>1</version>
<relativePath>../parent/pom.xml</relativePath>
</parent>
</project>
pom聚合
写Java时候, 聚合优于继承. 写xml也是一样.
<project>
<modelVersion>4.0.0</modelVersion>
<groupId>com.mycompany.app</groupId>
<artifactId>my-app</artifactId>
<version>1</version>
<packaging>pom</packaging>
<modules>
<module>my-module</module>
</modules>
</project>
这个modules
的写法, 就是聚合. 和java里是很像的.
依赖关系
回顾下上面的内容, pom 其实是一个一个节点对象,通过dependency互相关联. 如果抽象成Java结构是这样的.
class Project{
List<Project> dependencies;
}
这个结构比xml容易看, 一眼能看出来, 这是一个单根的树结构.mvn 其实也有这个概念, 依赖本来就是叫依赖树
的.
这个, 在intellij
仓库里, 有一个maven helper
插件, 用来分析这个非常好用. 强烈推荐.

重复依赖
这里有个问题, 普通的树,节点都是不一样的. 但是在pom里, 有可能出现A->B-C
,A-C
这种情况, 两方甚至更多方都依赖C.
这种情况下, maven的处理规则的, 就近原则.
会根据依赖树的深度来计算权重, 谁出现的层级更高,更靠近根,就会被选中, 这个叫nearest definition
.
A
├── B
│ └── C
│ └── D 2.0
└── E
└── D 1.0
这种情况, 选用D 1.0, 因为他只有2层, D2.0是在第三层. 图出自maven官网文档.
如果要解决重复依赖的问题,有两个方向
-
排除法 让树里不存在重复节点,自然解决问题 -
手动强行指定
排除法
这个是最简单的思路, 把依赖的排除掉,只保留一个,<exclusions>
就是做这个的.里面可以罗列上要排除内容.
有一个小技巧, 这里的排除是支持通配的. 甚至可以写成这样.除非知道自己在干什么,否则不推荐写到这么夸张.
<exclusions>
<exclusion>
<groupId>*</groupId>
<artifactId>*</artifactId>
</exclusion>
</exclusions>
强制指定 Dependency management
这是另一种思路.毕竟就近原则只是默认规则,如果手动指定, 是能盖掉这个规则的.
日常项目里经常看到的dep…m…元素,就是这个用途.
这项配置是在重复依赖里不排除的前提下, 手动指定版本号配置.版本号就会以配置为准,而不是根据最近原则了.
项目多继承问题
dependencyManagement还能解决另一个问题: 项目多继承.
Java中的类只能有一个父类. pom.xml这里也是相似的.如果想要打破这个规则, 也有变通的办法.
一般会借助dependencyManagement标签的import属性:
-
一个做父pom -
一个import.
日常使用spring cloud时候, 会这么引入.
<properties>
<spring.cloud-version>Hoxton.SR8</spring.cloud-version>
</properties>
<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>
这段<scope>import</scope>
就是import
内容. 用来解决多继承问题的.
好了, 今天就到这里. 不然12点前发不出去了. 我是一直在加班的老K. 我们回头再见.
原文始发于微信公众号(K字的研究):大白话解说maven初学者最好知道的一些事
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/24828.html