7. 搭建 Maven 私服:Nexus
很多公司都是搭建自己的 Maven 私有仓库,主要用于项目的公共模块的迭代更新等。
7.1 Nexus 下载安装
下载地址:https://download.sonatype.com/nexus/3/latest-unix.tar.gz
百度网盘:https://pan.baidu.com/s/12IjpSSUSZa6wHZoQ8wHsxg (提取码:5bu6)
百度链接: https://pan.baidu.com/s/1urwk4XfIl3lYUKuuDj6O2Q (提取码: tfb1 )
然后将下载的文件上传到 Linux 系统,解压后即可使用,不需要安装。但是需要注意:必须提前安装 JDK。(我这里放在 /root/nexus 下)
tar -zxvf nexus-3.25.1-04-unix.tar.gz
解压后如下:
通过以下命令启动:
# 启动 /root/nexus/nexus-3.25.1-04/bin/nexus start # 查看状态 /root/nexus/nexus-3.25.1-04/bin/nexus status
如果显示nexus is stopped.
则说明启动失败,通过命令查看端口占用情况:
netstart -luntp|grep java
可以看到 8081 端口被占用,而 nexus 的默认端口为 8081,我们可以修改其默认端口号,其配置文件在 etc
目录下的nexus-default.properties
,如下:
打开后修改为自己需要设置的端口,注意开启对外防火墙:
提示:
bin目录下 nexus.vmoptions 文件,可调整内存参数,防止占用内存太大。
etc目录下 nexus-default.properties 文件可配置默认端口和host及访问根目录。
然后访问 http://[Linux 服务器地址]:8081/
进入首页:
7.2 初始设置
点击右上角的登录:
这里参考提示:
- 用户名:admin
- 密码:查看 /opt/sonatype-work/nexus3/admin.password 文件
然后输入密码进行下一步:
匿名登录,启用还是禁用?由于启用匿名登录后,后续操作比较简单,这里我们演示禁用匿名登录的操作方式:
除了默认账号 admin,admin 具有全部权限,还有 anonymous,anonymous 作为匿名用户,只具有查看权限,但可以查看仓库并下载依赖。
完成:
7.3 Nexus Repository
nexus 默认创建了几个仓库,如下:
其中仓库 Type 类型为:
仓库类型 | 说明 |
proxy | 某个远程仓库的代理 |
group | 存放:通过 Nexus 获取的第三方 jar 包 |
hosted | 存放:本团队其他开发人员部署到 Nexus 的 jar 包 |
仓库名称:
仓库名称 | 说明 |
maven-central | Nexus 对 Maven 中央仓库的代理 |
maven-public | Nexus 默认创建,供开发人员下载使用的组仓库 |
maven-releasse | Nexus 默认创建,供开发人员部署自己 jar 包的宿主仓库,要求 releasse 版本 |
maven-snapshots | Nexus 默认创建,供开发人员部署自己 jar 包的宿主仓库,要求 snapshots 版本 |
其中 maven-public 相当于仓库总和,默认把其他 3 个仓库加进来一起对外提供服务了,另外,如果有自己建的仓库,也要加进该仓库才有用。
初始状态下,这几个仓库都没有内容:
7.4 创建 Nexus Repository
除了自带的仓库,有时候我们需要单独创建自己的仓库,按照默认创建的仓库类型来创建我们自己的仓库。
7.4.1 创建 Nexus 宿主仓库
点击左边导航栏中的 Repositories,如下图:
然后创建仓库,如下:
同理创建 releases 仓库,然后查看列表:
宿主仓库配置如下:
配置 | 说明 |
Repository ID | 仓库 ID。 |
Repository Name | 仓库名称。 |
Repository Type | 仓库的类型,如 hosted、proxy 等等。 |
Provider | 用来确定仓库的格式,一般默认选择 Maven2。 |
Repository Policy | 仓库的策略。 |
Default Local Storage Location | 仓库默认存储目录,例如 D:nexus-2.14.20-02-bundlesonatype-worknexusindexerbianchengbang_Snapshot_hosted_ctx。 |
Override Local Storage Location | 自定义仓库存储目录。 |
Deployment Policy | 仓库的部署策略。 |
Allow File Browsing | 用来控制是否允许浏览仓库内容,一般选择 true。 |
Include in Search | 用来控制该仓库是否创建索引并提供搜索功能。 |
Publish URL | 用来控制是否通过 URL 提供服务。 |
Not Found Cache TTL | 缓存某构件不存在信息的时间,默认取值为 1440,表示若某一个构件在仓库中没有找到,在 1440 分钟内再次接收到该构件的请求,则直接返回不存在信息,不会再次查找。 |
7.4.2 创建 Nexus 代理仓库
然后建一个代理仓库,用来下载和缓存中央仓库(或者阿里云仓库)的构件,这里选择 proxy:
然后创建:
代理仓库配置中,仓库 ID、仓库名称、Provider、Policy 以及 Default Local Storage Location 等配置的含义与宿主仓库相同,不再赘述。需要注意的是,代理仓库的 Repository Type 的取值是 proxy。
代理仓库配置如下表:
配置 | 说明 |
Remote Storage Location | 远程仓库或中央仓库的地址,它是 Nexus 代理仓库最重要得配置,必须输入有效值,通常取值为 https://repo1.maven.org/maven2/。 |
Download Remote Indexes | 是否下载远程仓库的索引。 |
Auto Blocking Enabled | 是否启用自动阻止,即当 Nexus 无法连接中央仓库或远程仓库时,是否一直等待。取值为 true 表示不再等待,直接通知客户端无法连接,并返回。 |
File Content Validation | 是否启用文件内容校验。 |
Checksum Policy | 配置校验和出错时的策略,用户可以选择忽略、警告、记录警告信息或拒绝下载等多种策略。 |
Artifact Max Age | 构件缓存的最长时间,对于发布版本仓库来说,默认值为 -1,表示构件缓存后,就一直保存着,不再重新下载。对于快照版本仓库来说,默认值为 1440 分钟,表示每隔一天重新缓存一次代理的构件。 |
Metadata Max Age | 仓库元数据缓存的最长时间。 |
Item Max Age | 项目缓存的最长时间。 |
7.4.3 创建 Nexus 仓库组
下面我们将创建一个仓库组,并将刚刚创建的 3 个仓库都聚合起来,这里选择 group,如下:
查看 Nexus 仓库列表,可以看到创建的仓库组已经创建完成,如下图:
7.5 通过 Nexus 下载 jar 包
由于初始状态下都没有内容,所以我们需要进行配置,我们先在本地的 Maven 的配置文件中新建一个空的本地仓库作为测试。
然后,把我们原来配置阿里云仓库地址的 mirror 标签改成下面这样:
<mirror> <id>maven-public</id> <mirrorOf>central</mirrorOf> <name>Maven public</name> <url>http://106.15.15.213:8090/repository/maven-public/</url> </mirror>
这里的 url 标签是这么来的:
把上图中看到的地址复制出来即可。如果我们在前面允许了匿名访问,到这里就够了。但如果我们禁用了匿名访问,那么接下来我们还要继续配置 settings.xml:
<server> <id>maven-public</id> <username>admin</username> <password>@123456</password> </server>
注意:server 标签内的 id 标签值必须和 mirror 标签中的 id 值一样。
然后找一个用到框架的 Maven 工程,编译 compile,下载过程日志:
下载后,Nexus 服务器上就有了 jar 包:
7.6 将 jar 包部署到 Nexus
这一步的作用是将通用的模块打成 jar 包,发布到 Nexus 私服,让其他的项目来引用,以更简洁高效的方式来实现复用和管理。
需要配置 server:
<server> <id>maven-public</id> <username>admin</username> <password>@123456</password> </server> <server> <id>maven-releases</id> <username>admin</username> <password>@123456</password> </server> <server> <id>maven-snapshots</id> <username>admin</username> <password>@123456</password> </server>
然后在我们需要上传的 maven 项目中的pom.xml
添加如下配置:
<!-- 这里的 id 要和上面的 server 的 id 保持一致,name 随意写--> <distributionManagement> <repository> <id>maven-releases</id> <name>Releases Repository</name> <url>http://106.15.15.213:8090/repository/maven-releases/</url> </repository> <snapshotRepository> <id>maven-snapshots</id> <name>Snapshot Repository</name> <url>http://106.15.15.213:8090/repository/maven-snapshots/</url> </snapshotRepository> </distributionManagement>
7.6.1 上传到 maven-snapshots
执行命令 mvn deploy
将当前 SNAPSHOT(快照版)上传到私服 maven-snapshots。
7.6.2 上传到 maven-releases
修改项目的版本,如下:
执行命令 mvn deploy
:
查看:
package 命令完成了项目编译、单元测试、打包功能。
install 命令完成了项目编译、单元测试、打包功能,同时把打好的可执行jar包(war包或其它形式的包)布署到本地maven仓库。
deploy 命令完成了项目编译、单元测试、打包功能,同时把打好的可执行jar包(war包或其它形式的包)布署到本地maven仓库和远程maven私服仓库。
8. jar 包冲突问题
先给结论:编订依赖列表的程序员。初次设定一组依赖,因为尚未经过验证,所以确实有可能存在各种问题,需要做有针对性的调整。那么谁来做这件事呢?我们最不希望看到的就是:团队中每个程序员都需要自己去找依赖,即使是做同一个项目,每个模块也各加各的依赖,没有统一管理。那前人踩过的坑,后人还要再踩一遍。而且大家用的依赖有很多细节都不一样,版本更是五花八门,这就让事情变得更加复杂。
所以虽然初期需要根据项目开发和实际运行情况对依赖配置不断调整,最终确定一个各方面都 OK 的版本。但是一旦确定下来,放在父工程中做依赖管理,各个子模块各取所需,这样基本上就能很好的避免问题的扩散。
即使开发中遇到了新问题,也可以回到源头检查、调整 dependencyManagement 配置的列表——而不是每个模块都要改。
8.1 表现形式
由于实际开发时我们往往都会整合使用很多大型框架,所以一个项目中哪怕只是一个模块也会涉及到大量 jar 包。数以百计的 jar 包要彼此协调、精密配合才能保证程序正常运行。而规模如此庞大的 jar 包组合在一起难免会有磕磕碰碰。最关键的是由于 jar 包冲突所导致的问题非常诡异,这里我们只能罗列较为典型的问题,而没法保证穷举。
但是我们仍然能够指出一点:一般来说,由于我们自己编写代码、配置文件写错所导致的问题通常能够在异常信息中看到我们自己类的全类名或配置文件的所在路径。如果整个错误信息中完全没有我们负责的部分,全部是框架、第三方工具包里面的类报错,这往往就是 jar 包的问题所引起的。
而具体的表现形式中,主要体现为找不到类或找不到方法。
8.1.1 抛异常:找不到类
此时抛出的常见的异常类型:
- java.lang.ClassNotFoundException:编译过程中找不到类
- java.lang.NoClassDefFoundError:运行过程中找不到类
- java.lang.LinkageError:不同类加载器分别加载的多个类有相同的全限定名
我们来举个例子:
<dependency> <groupId>org.apache.httpcomponents</groupId> <artifactId>httpclient</artifactId> <version>4.x.x</version> </dependency> 12345
httpclient 这个 jar 包中有一个类:org.apache.http.conn.ssl.NoopHostnameVerifier。这个类在较低版本中没有,但在较高版本存在。比如:
jar 包版本 | 是否存在 |
4.3.6 | 否 |
4.4 | 是 |
那当我们确实需要用到 NoopHostnameVerifier 这个类,我们看到 Maven 通过依赖传递机制引入了这个 jar 包,所以没有明确地显式声明对这个 jar 包的依赖。可是 Maven 传递过来的 jar 包是 4.3.6 版本,里面没有包含我们需要的类,就会抛出异常。
而『冲突』体现在:4.3.6 和 4.4 这两个版本的 jar 包都被框架所依赖的 jar 包给传递进来了,但是假设 Maven 根据『版本仲裁』规则实际采纳的是 4.3.6。
版本仲裁
Maven 的版本仲裁机制只是在没有人为干预的情况下,自主决定 jar 包版本的一个办法。而实际上我们要使用具体的哪一个版本,还要取决于项目中的实际情况。所以在项目正常运行的情况下,jar 包版本可以由 Maven 仲裁,不必我们操心;而发生冲突时 Maven 仲裁决定的版本无法满足要求,此时就应该由程序员明确指定 jar 包版本。
版本仲裁遵循以下规则:
- 最短路径优先
在下图的例子中,对模块 pro25-module-a 来说,Maven 会采纳 1.2.12 版本。
- 路径相同时先声明者优先
此时 Maven 采纳哪个版本,取决于在 pro29-module-x 中,对 pro30-module-y 和 pro31-module-z 两个模块的依赖哪一个先声明。
8.1.2 抛异常:找不到方法
程序找不到符合预期的方法。这种情况多见于通过反射调用方法,所以经常会导致:java.lang.NoSuchMethodError。
8.1.3 没报错但结果不对
发生这种情况比较典型的原因是:两个 jar 包中的类分别实现了同一个接口,这本来是很正常的。但是问题在于:由于没有注意命名规范,两个不同实现类恰巧是同一个名字。
具体例子是实际工作中遇到过:项目中部分模块使用 log4j 打印日志;其它模块使用 logback,编译运行都不会冲突,但是会引起日志服务降级,让你的 log 配置文件失效。比如:你指定了 error 级别输出,但是冲突就会导致 info、debug 都在输出。
8.2 本质
以上表现形式归根到底是两种基本情况导致的:
- 同一 jar 包的不同版本
- 不同 jar 包中包含同名类
这里我们拿 netty 来举个例子,netty 是一个类似 Tomcat 的 Servlet 容器。通常我们不会直接依赖它,所以基本上都是框架传递进来的。那么当我们用到的框架很多时,就会有不同的框架用不同的坐标导入 netty。可以参照下表对比一下两组坐标:
| 截止到3.2.10.Final版本以前的坐标形式: | 从3.3.0.Final版本开始以后的坐标形式: |
| :--------------------------------------------- | :------------------------------------- |
| org.jboss.nettynetty3.2.10.Final | io.nettynetty3.9.2.Final |
但是偏偏这两个『不同的包』里面又有很多『全限定名相同』的类。例如:
org.jboss.netty.channel.socket.ServerSocketChannelConfig.class org.jboss.netty.channel.socket.nio.NioSocketChannelConfig.class org.jboss.netty.util.internal.jzlib.Deflate.class org.jboss.netty.handler.codec.serialization.ObjectDecoder.class org.jboss.netty.util.internal.ConcurrentHashMap$HashIterator.class org.jboss.netty.util.internal.jzlib.Tree.class org.jboss.netty.util.internal.ConcurrentIdentityWeakKeyHashMap$Segment.class org.jboss.netty.handler.logging.LoggingHandler.class org.jboss.netty.channel.ChannelHandlerLifeCycleException.class org.jboss.netty.util.internal.ConcurrentIdentityHashMap$ValueIterator.class org.jboss.netty.util.internal.ConcurrentIdentityWeakKeyHashMap$Values.class org.jboss.netty.util.internal.UnterminatableExecutor.class org.jboss.netty.handler.codec.compression.ZlibDecoder.class org.jboss.netty.handler.codec.rtsp.RtspHeaders$Values.class org.jboss.netty.handler.codec.replay.ReplayError.class org.jboss.netty.buffer.HeapChannelBufferFactory.class …… 123456789101112131415161718
8.3 解决办法
很多情况下常用框架之间的整合容易出现的冲突问题都有人总结过了,拿抛出的异常搜索一下基本上就可以直接找到对应的 jar 包。我们接下来要说的是通用方法。
不管具体使用的是什么工具,基本思路无非是这么两步:
- 第一步:把彼此冲突的 jar 包找到
- 第二步:在冲突的 jar 包中选定一个。具体做法无非是通过 exclusions 排除依赖,或是明确声明依赖。
8.3.1 IDEA 的 Maven Helper 插件
这个插件是 IDEA 中安装的插件,不是 Maven 插件。它能够给我们罗列出来同一个 jar 包的不同版本,以及它们的来源。但是对不同 jar 包中同名的类没有办法。
然后基于 pom.xml 的依赖冲突分析,如下:
查看冲突分析结果:
8.3.2 Maven 的 enforcer 插件
使用 Maven 的 enforcer 插件既可以检测同一个 jar 包的不同版本,又可以检测不同 jar 包中同名的类。
这里我们引入两个对 netty 的依赖,展示不同 jar 包中有同名类的情况作为例子。
<dependencies> <dependency> <groupId>org.jboss.netty</groupId> <artifactId>netty</artifactId> <version>3.2.10.Final</version> </dependency> <dependency> <groupId>io.netty</groupId> <artifactId>netty</artifactId> <version>3.9.2.Final</version> </dependency> </dependencies>
然后配置 enforcer 插件:
<build> <pluginManagement> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-enforcer-plugin</artifactId> <version>1.4.1</version> <executions> <execution> <id>enforce-dependencies</id> <phase>validate</phase> <goals> <goal>display-info</goal> <goal>enforce</goal> </goals> </execution> </executions> <dependencies> <dependency> <groupId>org.codehaus.mojo</groupId> <artifactId>extra-enforcer-rules</artifactId> <version>1.0-beta-4</version> </dependency> </dependencies> <configuration> <rules> <banDuplicateClasses> <findAllDuplicates>true</findAllDuplicates> </banDuplicateClasses> </rules> </configuration> </plugin> </plugins> </pluginManagement> </build>
执行如下 Maven 命令:
mvn clean package enforcer:enforce
部分运行结果:
文章知识点与官方知识档案匹配,可进一步学习相关知识
9.拓展知识:
1.pom.xml配置详解信息:
<?xml version="1.0" encoding="utf-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0http://maven.apache.org/maven-v4_0_0.xsd"> <!--父项目的坐标。如果项目中没有规定某个元素的值, 那么父项目中的对应值即为项目的默认值。 坐标包括group ID,artifact ID和 version。--> <parent> <!--被继承的父项目的构件标识符--> <artifactId/> <!--被继承的父项目的全球唯一标识符--> <groupId/> <!--被继承的父项目的版本--> <version/> </parent> <!--声明项目描述符遵循哪一个POM模型版本。模型本身的版本很少改变,虽然如此, 但它仍然是必不可少的,这是为了当Maven引入了新的特性或者其他模型变更的时候, 确保稳定性。--> <modelVersion>4.0.0</modelVersion> <!--项目的全球唯一标识符,通常使用全限定的包名区分该项目和其他项目。 并且构建时生成的路径也是由此生成, 如com.mycompany.app生成的相对路径为: /com/mycompany/app --> <groupId>cn.missbe.web</groupId> <!-- 构件的标识符,它和group ID一起唯一标识一个构件。换句话说, 你不能有两个不同的项目拥有同样的artifact ID和groupID;在某个 特定的group ID下,artifact ID也必须是唯一的。构件是项目产生的或使用的一个东西, Maven为项目产生的构件包括:JARs,源码,二进制发布和WARs等。--> <artifactId>search-resources</artifactId> <!--项目产生的构件类型,例如jar、war、ear、pom。插件可以创建 他们自己的构件类型,所以前面列的不是全部构件类型--> <packaging>war</packaging> <!--项目当前版本,格式为:主版本.次版本.增量版本-限定版本号--> <version>1.0-SNAPSHOT</version> <!--项目的名称, Maven产生的文档用--> <name>search-resources</name> <!--项目主页的URL, Maven产生的文档用--> <url>http://www.missbe.cn</url> <!-- 项目的详细描述, Maven 产生的文档用。 当这个元素能够用HTML格式描述时 (例如,CDATA中的文本会被解析器忽略,就可以包含HTML标 签), 不鼓励使用纯文本描述。如果你需要修改产生的web站点的索引页面, 你应该修改你自己的索引页文件,而不是调整这里的文档。--> <description>A maven project to study maven.</description> <!--描述了这个项目构建环境中的前提条件。--> <prerequisites> <!--构建该项目或使用该插件所需要的Maven的最低版本--> <maven/> </prerequisites> <!--构建项目需要的信息--> <build> <!--该元素设置了项目源码目录,当构建项目的时候, 构建系统会编译目录里的源码。该路径是相对于pom.xml的相对路径。--> <sourceDirectory/> <!--该元素设置了项目脚本源码目录,该目录和源码目录不同: 绝大多数情况下,该目录下的内容 会被拷贝到输出目录(因为脚本是被解释的,而不是被编译的)。--> <scriptSourceDirectory/> <!--该元素设置了项目单元测试使用的源码目录,当测试项目的时候, 构建系统会编译目录里的源码。该路径是相对于pom.xml的相对路径。--> <testSourceDirectory/> <!--被编译过的应用程序class文件存放的目录。--> <outputDirectory/> <!--被编译过的测试class文件存放的目录。--> <testOutputDirectory/> <!--使用来自该项目的一系列构建扩展--> <extensions> <!--描述使用到的构建扩展。--> <extension> <!--构建扩展的groupId--> <groupId/> <!--构建扩展的artifactId--> <artifactId/> <!--构建扩展的版本--> <version/> </extension> </extensions> <!--这个元素描述了项目相关的所有资源路径列表,例如和项目相关的属性文件, 这些资源被包含在最终的打包文件里。--> <resources> <!--这个元素描述了项目相关或测试相关的所有资源路径--> <resource> <!-- 描述了资源的目标路径。该路径相对target/classes目录(例如${project.build.outputDirectory})。举个例 子,如果你想资源在特定的包里(org.apache.maven.messages),你就必须该元素设置为org/apache/maven /messages。 然而,如果你只是想把资源放到源码目录结构里,就不需要该配置。--> <targetPath/> <!--是否使用参数值代替参数名。参数值取自properties元素或者文件里配置的属性, 文件在filters元素里列出。--> <filtering/> <!--描述存放资源的目录,该路径相对POM路径--> <directory/> <!--包含的模式列表,例如**/*.xml.--> <includes/> <!--排除的模式列表,例如**/*.xml--> <excludes/> </resource> </resources> <!--这个元素描述了单元测试相关的所有资源路径,例如和单元测试相关的属性文件。--> <testResources> <!--这个元素描述了测试相关的所有资源路径,参见build/resources/resource元素的说明--> <testResource> <targetPath/> <filtering/> <directory/> <includes/> <excludes/> </testResource> </testResources> <!--构建产生的所有文件存放的目录--> <directory/> <!--产生的构件的文件名,默认值是${artifactId}-${version}。--> <finalName/> <!--当filtering开关打开时,使用到的过滤器属性文件列表--> <filters/> <!--子项目可以引用的默认插件信息。该插件配置项直到被引用时才会被解析或绑定到生命周期。 给定插件的任何本地配置都会覆盖这里的配置--> <pluginManagement> <!--使用的插件列表 。--> <plugins> <!--plugin元素包含描述插件所需要的信息。--> <plugin> <!--插件在仓库里的group ID--> <groupId/> <!--插件在仓库里的artifact ID--> <artifactId/> <!--被使用的插件的版本(或版本范围)--> <version/> <!--是否从该插件下载Maven扩展(例如打包和类型处理器),由于性能原因, 只有在真需要下载时,该元素才被设置成enabled。--> <extensions/> <!--在构建生命周期中执行一组目标的配置。每个目标可能有不同的配置。--> <executions> <!--execution元素包含了插件执行需要的信息--> <execution> <!--执行目标的标识符,用于标识构建过程中的目标,或者匹配继承过程中需要合并的执行目标--> <id/> <!--绑定了目标的构建生命周期阶段,如果省略,目标会被绑定到源数据里配置的默认阶段--> <phase/> <!--配置的执行目标--> <goals/> <!--配置是否被传播到子POM--> <inherited/> <!--作为DOM对象的配置--> <configuration/> </execution> </executions> <!--项目引入插件所需要的额外依赖--> <dependencies> <!--参见dependencies/dependency元素--> <dependency>......</dependency> </dependencies> <!--任何配置是否被传播到子项目--> <inherited/> <!--作为DOM对象的配置--> <configuration/> </plugin> </plugins> </pluginManagement> <!--使用的插件列表--> <plugins> <!--参见build/pluginManagement/plugins/plugin元素--> <plugin> <groupId/> <artifactId/> <version/> <extensions/> <executions> <execution> <id/> <phase/> <goals/> <inherited/> <configuration/> </execution> </executions> <dependencies> <!--参见dependencies/dependency元素--> <dependency>......</dependency> </dependencies> <goals/> <inherited/> <configuration/> </plugin> </plugins> </build> <!--模块(有时称作子项目) 被构建成项目的一部分。 列出的每个模块元素是指向该模块的目录的相对路径--> <modules/> <!--发现依赖和扩展的远程仓库列表。--> <repositories> <!--包含需要连接到远程仓库的信息--> <repository> <!--如何处理远程仓库里发布版本的下载--> <releases> <!--true或者false表示该仓库是否为下载某种类型构件(发布版,快照版)开启。 --> <enabled/> <!--该元素指定更新发生的频率。Maven会比较本地POM和远程POM的时间戳。这里的选项是:always(一直),daily(默认,每日),interval:X(这里X是以分钟为单位的时间间隔),或者never(从不)。--> <updatePolicy/> <!--当Maven验证构件校验文件失败时该怎么做:ignore(忽略),fail(失败),或者warn(警告)。--> <checksumPolicy/> </releases> <!-- 如何处理远程仓库里快照版本的下载。有了releases和snapshots这两组配置, POM就可以在每个单独的仓库中,为每种类型的构件采取不同的 策略。 例如,可能有人会决定只为开发目的开启对快照版本下载的支持。 参见repositories/repository/releases元素 --> <snapshots> <enabled/> <updatePolicy/> <checksumPolicy/> </snapshots> <!--远程仓库唯一标识符。可以用来匹配在settings.xml文件里配置的远程仓库--> <id>banseon-repository-proxy</id> <!--远程仓库名称--> <name>banseon-repository-proxy</name> <!--远程仓库URL,按protocol://hostname/path形式--> <url>http://192.168.1.169:9999/repository/</url> <!-- 用于定位和排序构件的仓库布局类型-可以是default(默认)或者legacy(遗留)。Maven 2为其仓库提供了一个默认的布局;然 而,Maven 1.x有一种不同的布局。我们可以使用该元素指定布局是default(默认)还是legacy(遗留)。--> <layout>default</layout> </repository> </repositories> <!--发现插件的远程仓库列表,这些插件用于构建和报表--> <pluginRepositories> <!--包含需要连接到远程插件仓库的信息.参见repositories/repository元素--> <pluginRepository>......</pluginRepository> </pluginRepositories> <!--该元素描述了项目相关的所有依赖。 这些依赖组成了项目构建过程中的一个个环节。 它们自动从项目定义的仓库中下载。要获取更多信息,请看项目依赖机制。--> <dependencies> <dependency> <!--依赖的group ID--> <groupId>org.apache.maven</groupId> <!--依赖的artifact ID--> <artifactId>maven-artifact</artifactId> <!--依赖的版本号。 在Maven 2里, 也可以配置成版本号的范围。--> <version>3.8.1</version> <!-- 依赖类型,默认类型是jar。它通常表示依赖的文件的扩展名,但也有例外 。一个类型可以被映射成另外一个扩展名或分类器。类型经常和使用的打包方式对应, 尽管这也有例外。一些类型的例子:jar,war,ejb-client和test-jar。 如果设置extensions为 true,就可以在 plugin里定义新的类型。所以前面的类型的例子不完整。--> <type>jar</type> <!-- 依赖的分类器。分类器可以区分属于同一个POM,但不同构建方式的构件。 分类器名被附加到文件名的版本号后面。例如,如果你想要构建两个单独的构件成 JAR, 一个使用Java 1.4编译器,另一个使用Java 6编译器,你就可以使用分类器来生成两个单独的JAR构件。--> <classifier/> <!--依赖范围。在项目发布过程中,帮助决定哪些构件被包括进来。欲知详情请参考依赖机制。 - compile :默认范围,用于编译 - provided:类似于编译,但支持你期待jdk或者容器提供,类似于classpath - runtime: 在执行时需要使用 - test: 用于test任务时使用 - system: 需要外在提供相应的元素。通过systemPath来取得 - systemPath: 仅用于范围为system。提供相应的路径 - optional: 当项目自身被依赖时,标注依赖是否传递。用于连续依赖时使用--> <scope>test</scope> <!--仅供system范围使用。注意,不鼓励使用这个元素, 并且在新的版本中该元素可能被覆盖掉。该元素为依赖规定了文件系统上的路径。 需要绝对路径而不是相对路径。推荐使用属性匹配绝对路径,例如${java.home}。--> <systemPath/> <!--当计算传递依赖时, 从依赖构件列表里,列出被排除的依赖构件集。 即告诉maven你只依赖指定的项目,不依赖项目的依赖。此元素主要用于解决版本冲突问题--> <exclusions> <exclusion> <artifactId>spring-core</artifactId> <groupId>org.springframework</groupId> </exclusion> </exclusions> <!--可选依赖,如果你在项目B中把C依赖声明为可选,你就需要在依赖于B的项目(例如项目A)中显式的引用对C的依赖。可选依赖阻断依赖的传递性。--> <optional>true</optional> </dependency> </dependencies> <!-- 继承自该项目的所有子项目的默认依赖信息。这部分的依赖信息不会被立即解析, 而是当子项目声明一个依赖(必须描述group ID和 artifact ID信息), 如果group ID和artifact ID以外的一些信息没有描述, 则通过group ID和artifact ID 匹配到这里的依赖,并使用这里的依赖信息。--> <dependencyManagement> <dependencies> <!--参见dependencies/dependency元素--> <dependency>......</dependency> </dependencies> </dependencyManagement> <!--项目分发信息,在执行mvn deploy后表示要发布的位置。 有了这些信息就可以把网站部署到远程服务器或者把构件部署到远程仓库。--> <distributionManagement> <!--部署项目产生的构件到远程仓库需要的信息--> <repository> <!--是分配给快照一个唯一的版本号(由时间戳和构建流水号)? 还是每次都使用相同的版本号?参见repositories/repository元素--> <uniqueVersion/> <id>banseon-maven2</id> <name>banseon maven2</name> <url>file://${basedir}/target/deploy</url> <layout/> </repository> <!--构件的快照部署到哪里?如果没有配置该元素,默认部署到repository元素配置的仓库, 参见distributionManagement/repository元素--> <snapshotRepository> <uniqueVersion/> <id>banseon-maven2</id> <name>Banseon-maven2 Snapshot Repository</name> <url>scp://svn.baidu.com/banseon:/usr/local/maven-snapshot</url> <layout/> </snapshotRepository> <!--部署项目的网站需要的信息--> <site> <!--部署位置的唯一标识符,用来匹配站点和settings.xml文件里的配置--> <id>banseon-site</id> <!--部署位置的名称--> <name>business api website</name> <!--部署位置的URL,按protocol://hostname/path形式--> <url>scp://svn.baidu.com/banseon:/var/www/localhost/banseon-web</url> </site> <!--项目下载页面的URL。如果没有该元素,用户应该参考主页。 使用该元素的原因是:帮助定位那些不在仓库里的构件(由于license限制)。--> <downloadUrl/> <!-- 给出该构件在远程仓库的状态。不得在本地项目中设置该元素, 因为这是工具自动更新的。有效的值有:none(默认), converted(仓库管理员从 Maven 1 POM转换过来),partner(直接从伙伴Maven 2仓库同步过来),deployed(从Maven 2实例部 署),verified(被核实时正确的和最终的)。--> <status/> </distributionManagement> <!--以值替代名称,Properties可以在整个POM中使用,也可以作为触发条件(见settings.xml配置文件里activation元素的说明)。格式是<name>value</name>。--> <properties/> </project>