读书笔记:给负面情绪降温,再寻求解决冲突问题。常见负面情绪有愤怒、悲伤、恐惧三大类。细分有生气、不满、伤心、担忧、缺少安全感等。识别自己的情绪、中性表达你所听到、看到的事实,不主观臆测,准确表达自己的情绪。此外,也需要疏导对方情绪,最后达成情绪共鸣,再寻求化解分歧和误会,找到解决方案。
一、前言背景
二、Maven是什么?
2.1 三大常用核心功能之依赖管理
2.2 三大常用核心功能之仓库管理
2.3 三大常用核心功能之项目构建
三、依赖是什么?从哪来?放哪里?
3.1 依赖里的scope是什么,有什么用?
3.2 依赖不在Maven仓库,怎么办?
四、如何解决依赖冲突?
4.1 Maven默认的解决方式
4.2 手工解决方式
4.3 其他方式
一、前言背景
Maven是什么?在很多初中级研发印象里,Maven只是系统项目里的一个pom.xml文件,甚至连mvn clean package命令都逐渐模糊。而项目研发技术leader、架构师已经把依赖管理、插件配置、整个系统的devops管理都做好了。大部分时间,大家只需要专注迭代完成系统业务功能开发。
然而,所有能被广泛应用的技术组件,背后必有超凡的设计和值得深入探索的技术价值。如果时间允许+自己也有兴趣,可以深入理解它的核心原理以及高阶特性。这个对我们研发技术经验积累和架构设计能力提升有极大帮助。
知识传播分享,不分高下,各有千秋。最近喜欢以专栏的形式,持续连载分享某个框架原理,也是希望能和有缘刷到且有兴趣的朋友,一起深入交流学习分享。也希望未来可以轻松的写一点新版本特性、或者只针对某个技术要点、生产故障进行详细探讨。
话不多说,今天正式开始我们的《Maven实战进阶系列》之旅。保持一贯风格,行文尽可能通俗易懂、图文并茂,以核心架构原理开局,力争以实战demo进阶,最后愿我们学海无涯,所见皆有所获。
二、Maven是什么?
Apache Maven是基于项目对象模型(POM)概念的项目管理构建工具。具有跨平台、标准化、自动化等特性。对于我们日常项目研发来说,Maven就是一个通过pom.xml文件来管理我们依赖包、插件、项目基础信息、项目构建的一个高度标准自动化的管理平台。
如果要说说Maven三大最常用、最核心的功能,我选择依赖管理、仓库管理、项目构建。
2.1 三大常用核心功能之依赖管理
首先,依赖管理,就是我们在pom里进行的项目依赖包的管理。我们只需要将依赖的第三方组件信息,通过dependency进行引入,maven就自动帮我们下载对应包以及管理它的生命周期。
2.2 三大常用核心功能之仓库管理
maven仓库有三种,一个是maven的中央仓库、一个是私服、一个是本地仓库。
在我们安装好maven后,本地有个仓库。比如我maven安装目录是:/Users/xxxx/soft/maven3.6.3。在该目录下,有个.m2目录,里面的repository文件夹,就是本地仓库。
查看本地仓库依赖包信息:ls .m2/repository
第二个私服。在企业里,公司需要搭建一个私有的公共maven仓库,方便存放管理内部各个研发项目的版本。此外,maven的中央仓库,由于是部署在国外,国内访问速度慢且网络不稳定。私服的存在,可以作为一个依赖缓存,避免研发依赖引入出现重复下载。
第三个,maven官方中央仓库https://mvnrepository.com/。这里存放共享着maven社区众多主流开源组件。基本上我们想要的依赖,在中央仓库都能找到。
此外,有些小公司,或者不需要搭建maven私服的企业,可以让研发人员配置国内主流远程仓库,比如阿里、清华仓库源,下载速度都非常快。
在.m2/settings.xml文件配置:
<settings xmlns="http://maven.apache.org/SETTINGS/1.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/SETTINGS/1.0.0 https://maven.apache.org/xsd/settings-1.0.0.xsd"> <mirrors> <mirror> <id>alimaven</id> <name>aliyun maven</name> <url>http://maven.aliyun.com/nexus/content/groups/public/</url> <mirrorOf>central</mirrorOf> </mirror> </mirrors> </settings>
2.3 三大常用核心功能之项目构建
日常项目构建,从代码编写就已经开始,写代码引入的包类需要maven管理构建引入,此后代码编译测试、运行、打包等过程都是项目构建流程内容。
在maven里,项目构建和生命周期密切相关。甚至就是maven通过生命周期来统一管理项目的构建过程。可以说项目构建管理,就是maven的生命周期管理。生命周期包括:清理、编译、测试、打包、部署、发布等过程。应用也非常简单,直接是mvn 后加生命周期名字即可,比如:mvn clean package。
这块内容会非常多,开篇我们简单了解即可,后续出一篇文章专门讲生命周期这块。
三、依赖是什么?从哪来?放哪里?
依赖就是我们系统项目依赖的第三方组件,比如fastjson、commons-langs组件。
在2.1我们也说过,在pom里 的 进行引入。这些依赖包,maven首先会从本地.m2仓库查找,如果没有找到,就从配置的远程仓库里找,一般是公司私服。如果公司私服也没有,私服就从远程仓库里下载。下载之后,存放在本地仓库。
3.1 依赖里的scope是什么,有什么用?
依赖里,除了groupId,artifactId,version,还有一个scope标签。比如我们日常用来做测试用的junit、Springboot test插件:
<dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <scope>test</scope> <version>3.8.2</version> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency>
这个scope标签,就是我们依赖包使用范围。它有6个范围:compile、provided、runtime、test、system、import。用的最多默认值complie。
如果scope是complie,那依赖包可以使用范围最广,从编译、测试、运行均会被应用。
而test,就是在我们test代码里可以使用。如果尝试在主代码main里使用scope为test的依赖,就会报错。
这块很有意思,如果时间允许,可以自己实践改不同scope去测试验证。
对我们来说,如果使用不多,其实这块不需要太关注,因为在我们去中央仓库查找时候,官方已经给了推荐默认值,我们直接使用即可。
3.2 依赖不在Maven仓库,怎么办?
现实里,有些特殊依赖包,并没有共享上传到maven的中央仓库、而且公司私服也没有。这种包,我们可以通过打包上传到私服。然后再在项目里引用。如果仅仅是本地使用,可以直接放到自己电脑Maven本地仓库。
四、如何解决依赖冲突?
在maven依赖管理里,什么是依赖冲突?
这个是初级开发、尤其是校招生面试的时候,经常被问到的基础问题。以及刚才所探讨的几个小问题。
依赖冲突,实际是多个组件依赖的同一个第三方组件,但是版本不一致问题。比如,项目引入了pring-boot-starter-log4j2、以及commons-logging组件,但是两者底层都依赖了log4j-core,且版本不一致:
spring-boot-starter-log4j2 ,依赖log4j-core 版本2.23.1。
commons-logging 也依赖了log4j-core ,但是版本2.24.3。
4.1 Maven默认的解决方式
Maven对依赖冲突解决很简单:依赖版本不一致,就进行N选1(gradle更简单,直接是取最新版本为准)。不过这个N选1,maven有2个原则:
第一声明优先原则。在pom文件里,哪个依赖所处位置更靠前,就是优先声明,默认被引入进来。后续的冲突依赖,就不会被依赖进来(除非手工解决干预)。
路径最近优先原则。依赖是有传递性的,比如项目直接依赖了A组件V1.0、B组件。而B组件依赖了A组件的V2.0。由于V1.0的A组件,是被项目直接引入,那A组件的V1.0被引入。冲突的V2.0不会被引入。
4.2 手工解决方式
对于冲突依赖,maven支持手工依赖排除,通过exclusion标签去设置。比如:
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> <exclusions> <exclusion> <artifactId>accessors-smart</artifactId> <groupId>net.minidev</groupId> </exclusion> </exclusions> </dependency>
此外,手工指定版本。有点类似4.1说的路径最近优先原则。比如项目直接引入依赖A、B组件。而A和B分别依赖C的V1和V2版本。这时候我们可以直接在项目里引入C组件,并指定对应版本来解决冲突。
4.3 其他方式
比如我们内部自研基础组件项目服务A依赖是pinyin4j。当我们打包服务A给其他项目使用,避免依赖pinyin4j给其他服务造成影响,我们设置pinyin4j的依赖进行依赖阻断。依赖阻断就是通过 设置为true来实现。比如:
<dependency> <groupId>com.belerweb</groupId> <artifactId>pinyin4j</artifactId> <version>2.5.1</version> <optional>true</optional> </dependency>
这样就可以避免其他服务在应用我们的基础组件时,需要手工解决依赖冲突问题。
推荐阅读拉丁解牛相关专题系列(欢迎交流讨论):
2、JVM进阶调优系列(2)字节面试:JVM内存区域怎么划分,分别有什么用?