一、坐标
找到唯一包需要指定的元素
二、依赖传递
A依赖B,B依赖C,那么A引用B的时候,不需要再将C依赖添加进Pom.xml
1、排除依赖
传递性依赖会给项目隐式地引入很多依赖,这极大地简化了项目依赖的管理,但是有时候这种特性也会带来问题。比如有种情况:
当前项目依赖A,A由于某些原因依赖了另外一个类库的SNAPSHOT版本,那么这个SNAPSHOT就会成为当前项目的传递性依赖,二SNAPSHOT的不稳定性将直接影响到当前的项目,此时就需要排除该SNAPSHOT,并且在当前项目中声明该类库的某个正式发布的版本
排除依赖很简单,看一下写法:
<dependency>
<groupId>com.alibaba.rocketmq</groupId>
<artifactId>rocketmq-client</artifactId>
<version>3.2.7</version>
<exclusions>
<exclusion>
<groupId>apache-lang</groupId>
<artifactId>commons-lang</artifactId>
</exclusion>
</exclusions>
</dependency>
三、Maven仓库(repository )
Maven仓库可简单分成两类: 本地仓库与远程仓库. 当Maven根据坐标寻找构件时, 它会首先检索本地仓库, 如果本地存在则直接使用, 否则去远程仓库下载.
本地仓库: 默认地址为~/.m2/, 一个构件只有在本地仓库存在之后, 才能由Maven项目使用。
远程仓库: 远程仓库又可简单分成: 中央仓库和私服以及第三方库(第三方库比较常用,如阿里云仓库: http://maven.aliyun.com/nexus/content/groups/public ,中央仓库比较慢,我们一般情况下都会镜像到国内的库)。
中央仓库:http://repo1.maven.org/maven2/
由于原始的本地仓库是空的, Maven必须至少知道一个远程仓库才能在执行命令时下载需要的构件, 中央仓库就是这样一个默认的远程仓库,仓库ID:maven依赖之central.
一方库、二方库、三方库说明:
一方库:本工程中的各模块的相互依赖
二方库:公司内部的依赖库,一般指公司内部的其他项目发布的jar包
三方库:公司之外的开源库, 比如apache、ibm、google等发布的依赖
1、私服
私服是一种特殊的远程仓库, 它设在局域网内, 通过代理广域网上的远程仓库, 供局域网内的Maven用户使用.
当需要下载构件时, Maven客户端先向私服请求, 如果私服不存在该构件, 则从外部的远程仓库下载, 并缓存在私服上, 再为客户提供下载服务
将包上传到私服(发布)
1.1、配置发布源
<distributionManagement>
<snapshotRepository>
<id>${repository.debug.id}</id>
<name>${repository.debug.name}</name>
<url>${repository.debug.url}</url>
</snapshotRepository>
<repository>
<id>${repository.release.id}</id>
<name>${repository.release.name}</name>
<url>${repository.release.url}</url>
</repository>
</distributionManagement>
repository:即产出物或下载源的仓库
repository
表示发布版本构件的仓库,snapshotRepository
代表快照版本的仓库.id
为该远程仓库唯一标识,url
表示该仓库地址.- 配置正确后, 执行
$ mvn clean deploy
则可以将项目构建输出的构件部署到对应配置的远程仓库.
顺便记录下,hubble-sdk部署到私服执行命令:mvn clean deploy -Dmaven.test.skip=true
有时候加clean的时候会报错,可以直接杀掉java进程即可,参考:快速解决Maven工程运行报错Failed to clean project: Failed to delete_Jia_Li_z的博客-CSDN博客
1.2、配置权限
需要修改的conf/setting.xml(conf下的setting.xml是全局配置),增加权限配置:
<!-- 私服发布的用户名密码 -->
<servers>
<server>
<id>没搞明白这是干嘛的</id>
<username>用户名</username>
<password>密码</password>
</server>
<server>
<id>xxx</id>
<username>用户名</username>
<password>密码</password>
</server>
</servers>
2、仓库配置
当不使用仓库时,默认使用的仓库地址是:https://repo.maven.apache.org/maven2
如下不配置仓库地址:
项目执行Maven install时:
5、profile标签
maven中profile元素的作用意义和用法_brave_zhao的博客-CSDN博客_maven中profile
Profile能让你为一个特殊的环境自定义一个特殊的构建;profile使得不同环境间构建的可移植性成为可能。Maven中的profile是一组可选的配置,可以用来设置或者覆盖配置默认值。有了profile,你就可以为不同的环境定制构建。profile可以在pom.xml中配置,并给定一个id。然后你就可以在运行Maven的时候使用的命令行标记告诉Maven运行特定profile中的目标。一个Profiles下面允许出现的元素:
<project> <profiles> <profile> <build> <defaultGoal>...</defaultGoal> <finalName>...</finalName> <resources>...</resources> <testResources>...</testResources> <plugins>...</plugins> </build> <reporting>...</reporting> <modules>...</modules> <dependencies>...</dependencies> <dependencyManagement>...</dependencyManagement> <distributionManagement>...</distributionManagement> <repositories>...</repositories> <pluginRepositories>...</pluginRepositories> <properties>...</properties> </profile> </profiles> </project>
一个Profile可以覆盖项目构件的最终名称,项目依赖,插件配置以影响构建行为,Profile还可以覆盖分发配置。maven提供了一种针对不同环境参数“激活”一个profile的方式,这就叫做profile激活。
profile简介
profile可以让我们定义一系列的配置信息,然后指定其激活条件。这样我们就可以定义多个profile,然后每个profile对应不同的激活条件和配置信息,从而达到不同环境使用不同配置信息的效果。比如说,我们可以通过profile定义在jdk1.5以上使用一套配置信息,在jdk1.5以下使用另外一套配置信息;或者有时候我们可以通过操作系统的不同来使用不同的配置信息,比如windows下是一套信息,linux下又是另外一套信息,等等。
profile的定义位置
我们可以有多个地方定义profile。定义的地方不同,它的作用范围也不同。
- 针对于特定项目的profile配置我们可以定义在该项目的pom.xml中。
- 针对于特定用户的profile配置,我们可以在用户的settings.xml文件中定义profile。该文件在用户家目录下的“.m2”目录下。
- 全局的profile配置。全局的profile是定义在Maven安装目录下的“conf/settings.xml”文件中的。
profile中能定义的信息
profile中能够定义的配置信息跟profile所处的位置是相关的。以下就分两种情况来讨论,一种是定义在settings.xml中,另一种是定义在pom.xml中。
profile定义在settings.xml中
当profile定义在settings.xml中时意味着该profile是全局的,它会对所有项目或者某一用户的所有项目都产生作用。因为它是全局的,所以在settings.xml中只能定义一些相对而言范围宽泛一点的配置信息,比如远程仓库等。而一些比较细致一点的需要根据项目的不同来定义的就需要定义在项目的pom.xml中。具体而言,能够定义在settings.xml中的信息有<repositories>、<pluginRepositories>和<properties>。定义在<properties>里面的键值对可以在pom.xml中使用。
四、Maven打包
1、打包
mvn clean package依次执行了clean、resources、compile、testResources、testCompile、test、jar(打包)等7个阶段。
mvn clean install依次执行了clean、resources、compile、testResources、testCompile、test、jar(打包)、install等8个阶段。
mvn clean deploy依次执行了clean、resources、compile、testResources、testCompile、test、jar(打包)、install、deploy等9个阶段。
由上面的分析可知主要区别如下,
package命令完成了项目编译、单元测试、打包功能,但没有把打好的可执行jar包(war包或其它形式的包)布署到本地maven仓库和远程maven私服仓库
install命令完成了项目编译、单元测试、打包功能,同时把打好的可执行jar包(war包或其它形式的包)布署到本地maven仓库,但没有布署到远程maven私服仓库
deploy命令完成了项目编译、单元测试、打包功能,同时把打好的可执行jar包(war包或其它形式的包)布署到本地maven仓库和远程maven私服仓库。
2、构件发布到远程
本地Maven仓库的构件只能供当前用户使用,在分发到远程Maven仓库(通过命令:mvn clean deploy)之后,所有能访问该仓库的用户都能使用你的构件。我们需要配置POM的distributionManagement标签来指定Maven分发构件的位置
关于distributionManagement:
2.1、发布源配置
Maven区别对待release版本的构件和snapshot版本的构件,snapshot为开发过程中的版本,实时,但不稳定,release版本则比较稳定。Maven会根据你项目的版本来判断将构件分发到哪个仓库。 配置如下:
<distributionManagement>
<snapshotRepository>
<id>${repository.debug.id}</id>
<name>${repository.debug.name}</name>
<url>${repository.debug.url}</url>
</snapshotRepository>
<repository>
<id>${repository.release.id}</id>
<name>${repository.release.name}</name>
<url>${repository.release.url}</url>
</repository>
</distributionManagement>
2.2、权限配置
分发构件到远程仓库需要认证,如果你没有配置任何认证信息,你往往会得到401错误。这个时候,如下在settings.xml中配置认证信息:
<servers>
<server>
<id>maven-snapshot</id>
<username>xxx</username>
<password>xxx</password>
</server>
<server>
<id>maven-release</id>
<username>xxx</username>
<password>xxx</password>
</server>
</servers>
需要注意的是,settings.xml中server元素下id的值必须与POM中repository或snapshotRepository下id的值完全一致(精确到对哪个发布源的认证)。将认证信息放到settings下而非POM中,是因为POM往往是它人可见的,而settings.xml是本地的。 私服中的每个库(不同的库不同的id地址标识,如下所示,所以server的id代表的即仓库地址,亲测,修改了id之后,deploy的时候就报401错误,即无权限)都可以配单独的账号密码,更加细化权限的控制。
五、Maven快照版本和发布版本
参考:maven快照版本和发布版本
在使用maven过程中,我们在开发阶段经常性的会有很多公共库处于不稳定状态,随时需要修改并发布,可能一天就要发布一次,遇到bug时,甚至一天要发布N次。我们知道,maven的依赖管理是基于版本管理的,对于发布状态的artifact,如果版本号相同,即使我们内部的镜像服务器上的组件比本地新,maven也不会主动下载的。如果我们在开发阶段都是基于正式发布版本来做依赖管理,那么遇到这个问题,就需要升级组件的版本号,可这样就明显不符合要求和实际情况了。但是,如果是基于快照版本,那么问题就自热而然的解决了,而maven已经为我们准备好了这一切。
maven中的仓库分为两种,snapshot快照仓库和release发布仓库。snapshot快照仓库用于保存开发过程中的不稳定版本,release正式仓库则是用来保存稳定的发行版本。定义一个组件/模块为快照版本,只需要在pom文件中在该模块的版本号后加上-SNAPSHOT即可(注意这里必须是大写),如下:
<groupId>cc.mzone</groupId>
<artifactId>m1</artifactId>
<version>0.1-SNAPSHOT</version>
<packaging>jar</packaging>
maven2会根据模块的版本号(pom文件中的version)中是否带有-SNAPSHOT来判断是快照版本还是正式版本。如果是快照版本,那么在mvn deploy时会自动发布到快照版本库中,会覆盖老的快照版本,而在使用快照版本的模块,在不更改版本号的情况下,直接编译打包时,maven会自动从镜像服务器上下载最新的快照版本。如果是正式发布版本,那么在mvn deploy时会自动发布到正式版本库中,而使用正式版本的模块,在不更改版本号的情况下,编译打包时如果本地已经存在该版本的模块则不会主动去镜像服务器上下载。
六、repository标签
repository:即Maven中的仓库,是构件(artifact)的集合。构件以一定的布局存储在库中。
根据构件的用途,构件可以分为两类:
一类是被其他构件依赖的构件(dependencies),这也是Maven库中主要的构件。
另一类是插件(plugins),这是一种特殊的构件。对于依赖的构件,其所在的库通过<repositories>设置。但是对于插件的构件,由于插件的特殊性,所以插件库独立于依赖库,使用<pluginRepositories>单独设置。但是由于依赖和插件都属于构件,所以<repositories>和<pluginRepositories>中的设置基本一致。
如果一个项目需要依赖一个构件,Maven编译的时候会首先从本地库查找该构件。如果本地库中没有,再根据配置的远程库信息,逐个去远程库中查找该构件。
如果在远程库中找到则下载到本地库,如果在所有的远程库中都没有则会抛出编译异常。
Maven中要配置库,可以有多种方式。
- 最直接的是在项目中的pom.xml文件中,通过<repositories>配置库,这样配置的库仅适用于当前项目。
- 也可以通过<profiles>中的<repositories>配置在特定环境下的特殊库,这可以在项目的pom.xml文件中实现,也可以在Maven的settings.xml中实现。
- 此外,一个项目发布后,其往往要被部署到一个库中,作为库的构件以供其他项目引用。通过<distributionManagement>中的<repositories>配置要发布的库。
七、Maven仓库优先级
Maven仓库理解和优先级 | ShenWenFang
八、Maven镜像(<mirrors>)
介绍
如果仓库X可以提供仓库Y存储的所有内容,那么就可以认为X是Y的一个镜像。换句话说,任何一个可以从仓库Y获得的构件,都能够从它的镜像中获取。mirror相当于一个拦截器,它会拦截maven对remote repository的相关请求,把请求里的remote repository地址,重定向到mirror里配置的地址 。
参考:https://my.oschina.net/sunchp/blog/100634
为什么要镜像
提升访问速度。
没有配置mirror :
配置了mirror:
repository与mirror的理解:
1.repository是指在局域网内部搭建的repository,它跟central repository, jboss repository等的区别仅仅在于其URL是一个内部网址
2.mirror则相当于一个代理,它会拦截去指定的远程repository下载构件的请求,然后从自己这里找出构件回送给客户端。配置mirror的目的一般是出于网速考虑。
<mirrors>
<mirror>
<id>xxx</id>
<mirrorOf>*</mirrorOf>
<name>Human Readable Name for this Mirror.</name>
<url>xxxurl</url>
</mirror>
<mirror>
<id>xxx</id>
<mirrorOf>*</mirrorOf>
<name>jcenter</name>
<url>xxxurl</url>
</mirror>
</mirrors>
高级的镜像配置:
1.<mirrorOf>*</mirrorOf>
匹配所有仓库请求,即将所有的仓库请求都转到该镜像上
2.<mirrorOf>external:*</mirrorOf>
匹配所有远程仓库,使用localhost的除外,使用file://协议的除外。也就是说,匹配所有不在本机上的远程仓库。
3.<mirrorOf>repo1,repo2</mirrorOf>
将仓库repo1和repo2的请求转到该镜像上,使用逗号分隔多个远程仓库。
4.<mirrorOf>*,!repo1</miiroOf>
匹配所有远程仓库,repo1除外,使用感叹号将仓库从匹配中排除。
mirrors可以配置多个mirror:
每个mirror有id,name,url,mirrorOf属性,id是唯一标识一个mirror就不多说了,name貌似没多大用,相当于描述,url是官方的库地址,mirrorOf代表了一个镜像的替代位置,例如central就表示代替官方的中央库。
多个mirror的使用顺序:
我本以为镜像库是一个分库的概念,就是说当a.jar在第一个mirror中不存在的时候,maven会去第二个mirror中查询下载。但事实却不是这样,当第一个mirror中不存在a.jar的时候,并不会去第二个mirror中查找,甚至于,maven根本不会去其他的mirror地址查询。
后来终于知道,maven的mirror是镜像,而不是“分库”,只有当前一个mirror无法连接的时候,才会去找后一个,类似于备份和容灾。
还有,mirror也不是按settings.xml中写的那样的顺序来查询的。
所谓的第一个并不一定是最上面的那个。
当有id为B,A,C的顺序的mirror在mirrors节点中,maven会根据字母排序来指定第一个,所以不管怎么排列,一定会找到A这个mirror来进行查找,当A无法连接,出现意外的情况下,才会去B查询。
九、Maven 多模块开发
好处:代码重用,如service模块,新起一个模块,直接引入service模块即可。
见另一篇博客:Maven学习记录之多模块开发 - 巍巍的个人页面 - OSCHINA - 中文开源技术交流社区
参考资料:
打包:https://blog.csdn.net/zhaojianting/article/details/80324533
原理:https://blog.csdn.net/zjf280441589/article/details/53044308/
Maven实战:pom.xml与settings.xml:https://www.cnblogs.com/xrq730/p/5530069.html
十、Maven依赖关系中Scope的作用
* compile,缺省值,适用于所有阶段,会随着项目一起发布。即打包的时候会把这个包打进去。
* provided,类似compile,期望JDK、容器或使用者会提供这个依赖。如servlet.jar。 但是容器可能已经有这个包了,因此不会随打包的时候一起打进去。这样可以避免想servlet-api.jar这样的jar包冲突,但是如果遇到idea下默认不提供servlet-api.jar时,使用scope=provided就会缺少对应的jar包,也就是我遇到的问题找不到类
* runtime,只在运行时使用,如JDBC驱动,适用运行和测试阶段。
* test,只在测试时使用,用于编译和运行测试代码。不会随项目发布。
* system,类似provided,需要显式提供包含依赖的jar,Maven不会在Repository中查找它。
小知识点之<scope>test</scope>
<!-- https://mvnrepository.com/artifact/org.slf4j/slf4j-log4j12 -->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<version>1.7.25</version>
<scope>test</scope>
</dependency>
<scope>test</scope>
maven在编译的时候,src/main/java下是不引用<scope>test</scope>的jar,而编译src/test/java下的测试这会引用<scope>test</scope>的jar
如下图所示:在src/main/java中报错了,但是在src/test/java下没有报错
七、Linux安装Maven
下载maven并配置环境变量,maven就生效了
配置maven环境变量
vi /etc/profile
添加环境变量
export MAVEN_HOME=/var/local/apache-maven-3.5.2
export MAVEN_HOME
export PATH=$PATH:$MAVEN_HOME/bin
编辑之后记得使用source /etc/profile命令是改动生效。
参考:
Maven的标准settings.xml文件
记录settings.xml的配置,理解mirror、repository、profile的关系