简介
nexus是一个强大的maven仓库管理器,它极大的简化了本地内部仓库的维护和外部仓库的访问.
nexus是一套开箱即用的系统不需要数据库,它使用文件系统加Lucene来组织数据
nexus使用ExtJS来开发界面,利用Restlet来提供完整的REST APIs,通过IDEA和Eclipse集成使用
nexus支持webDAV与LDAP安全身份认证.
nexus提供了强大的仓库管理功能,构件搜索功能,它基于REST,友好的UI是一个extjs的REST客户端,占用较少的内存,基于简单文件系统而非数据库.
下载nexus
https://www.sonatype.com/nexus/repository-oss
Business Email*企业邮箱
链接:https://pan.baidu.com/s/1XxmuONZDYkkxY7Az2ltR4g
提取码:b2vp
安装启动nexus3.x
下载好的压缩包,进行解压。
熟悉nexus结构
目录结构
根目录
-
nexus-3.34.0-01
安装目录 -
sonatype-work\nexus3
数据文档
nexus-3.34.0-01 目录
bin
包含nexus的启动脚本和相关配置etc
jetty、karaf等配置文件jre
jre环境lib
java架包库public
关于nexus应用在本地跑起来所需要的资源system
应用所有的插件和组件LICENSE.txt
和NOTICE.txt
版权声明和法律细则
sonatype-work\nexus3 目录
blobs/
创建blob的默认路径,当然也可以重新指定cache/
当前缓存的karaf包的信息db/ OrientDB
数据库的数据,用于存储nexus的元数据的数据库elasticsearch/
当前配置的Elasticsearch状态etc/
大概是运行时配置状态和关于资源库的自定义的相关的东西health-check/
看目录,健康检查的相关报告的存储目录吧keystores/
自动生成的关于资源库的ID主键log/
运行实例生成的日志文件,也有日志文件的压缩包,貌似是每天都会生成日志文件,你可以定期删除老的日志文件tmp/
用于存储临时文件的目录
具体每个目录下的各个配置文件的作用,还可参考官方文档说明:https://help.sonatype.com/display/NXRM3/Installation
如果想配置 nexus 的应用在本地启动的 JVM参数,可以在 nexus.vmoptions
如果想改变 nexus 的 端口号,可以在 nexus-default.properties
启动方式
- 直接启动 nexus.exe /run
以管理身份运行cmd(右击开始),进入到解压后nexus.exe所在目录
Windows输入 nexus.exe /run,回车即可运行
Could not open SCManager.是没以管理员身份运行
运行成功
- 将nexus配置为系统服务
根据官方文档说明,将nexus配置为系统服务是一个很好的选择。因为:
上面的安装和启动过程并没有默认的把 nexus 作为服务加入系统服务中;
这样下次服务器重启,服务也会重启。
但是有个前提,就是已经确保安装了Java运行时环境。
接下来,我们重新打开一个窗口,去将nexus加入系统服务 :
的配置:直接命名成 nexus 就好。【当然不指定的话,默认就是创建成 nexus 服务名】
ps:如果在windows上安装nexus为系统服务时,报错:could not open SCManager 。则需要 以管理员身份运行 cmd ,然后重新执行。
nexus /install nexus
nexus /uninstall nexus3
nexus /start nexus
nexus /stop nexus
访问 Nexus 用户页面
Nexus 启动成功之后,就会监听配置的IP地址和接口范围,默认的接口是 8081,在浏览器访问 http://localhost:8081/,可以看到启动的本地 Nexus 仓库页面。如果别人想访问这个仓库的话,需要额外配置。
服务启动成功后可以从浏览器中打开 nexus 管理后台并登陆。默认用户名为 admin ,默认密码为 admin123
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-tmpBJPO3-1636099692104)(C:\Users\hengdawb\Desktop\maven.assets\image-20210914141529052.png)]
用户名或密码不正确,或者没有使用该应用程序的权限
去提示的目录复制你的密码进行登录,默认密码不是admin123,密码在文件admin.password中,路径是解压文件的然后重新设置密码就可以了,文件路径在 nexus/sonatype-work/nexus3/ 下面
第一次进入按照提示修改密码和配置
禁用匿名访问
访问 Nexus 仓库分类
打开 Nexus 的 Repository 页面,可以看到 Nexus 默认为我们创建的仓库。
注意 Type 列,展示了 Nexus 的仓库分类:
proxy(远程代理仓库)
这种类型的仓库,可以设置一个远程仓库的链接。当用户向 proxy 类型仓库请求下载一个依赖构件时,就会先在自己的库里查找,如果找不到的话,就会从设置的远程仓库下载到自己的库里,然后返回给用户,相当于起到一个中转的作用。
例如 maven-central 用来存储从 Maven 中央仓库下载过的构件。
group (聚合仓库)
在 Maven 里没有这个概念,是 Nexus 特有的。目的是将多个仓库聚合,对用户暴露统一的地址,这样用户就不需要配置多个地址,只要统一配置 group 的地址就可以了。group 仓库的聚合成员可以在仓库设置中添加和移除。
仓库组的概念,目的是将多个仓库聚合,对用户暴露统一的地址,当需要获取某一个依赖包时,请求的是Group的地址,系统将会根据Group配置的仓库顺序依次查找。
例如 maven-public 是一个 group 类型的仓库,通过引用这个地址,可以访问组内成员仓库的所有构件。
hosted(宿主仓库)
我们自己的构件,上传的就是这样的仓库。目前 maven-releases 和 maven-snapshots 是 hosted 类型的仓库。我们可以上传到这两个仓库,也可以自己创建 hosted 仓库。
上传依赖包到 Nexus 私库
使用 Gradle 的集成的 Maven 插件上传
Gradle 集成了 Maven plugin,通过简单的配置,就能将构件上传到 Maven 服务器上。
- 第一步,创建一个 Android Library 项目
- 第二步,Library Moudle 的 build.gradle 配置上传参数
- 第三步,上传到 nexus 私服。
上传bugfix
gradlew --version
改完后不起作用重启AS。
gradlew publish
release 和 snapshot 仓库的区别与正确使用
上个步骤,我们已经将将依赖构件上传到 release 仓库中,如果没有修改版本号,再次上传,就会上传失败,并提示如下错误:
Error:Execution failed for task ‘:nexuslibrary:uploadArchives’.`
Could not publish configuration ‘archives’
Failed to deploy artifacts: Could not transfer artifact com.dr:nexuslibrary:aar:1.0.0 from/to remote (http://localhost:8081/repository/maven-releases/): Failed to transfer file: http://localhost:8081/repository/maven-releases/com/dr/nexuslibrary/1.0.0/nexuslibrary-1.0.0.aar. Return code is: 400, ReasonPhrase: Repository does not allow updating assets: maven-releases.
原因在于,release 仓库不能重复上传同一版本号,版本不能覆盖,只能迭代。
snapshot 仓库允许版本覆盖。当上传多次上传同一个版本到 snapshot 仓库,会自动在版本号上添加时间戳来区分。
那么问题来了,为什么存在这两个仓库?这个区别的存在意义是什么呢?
试想你是一个三方库的开发者,三方库是对外暴露的,1.0.0 已经在为其他程序服务,同时它本身存在问题也在继续开发迭代。此刻正在开发新版本 1.0.1,公司的小伙伴在同步从 Nexus 私库下载 1.0.1 最新改动版本测试。这种情况需要保证:
对外版本 1.0.0 不受影响
内测小伙伴始终能拉取到 1.0.1 的最新版本。
从版本号上,可以区分测试版和对外开放的稳定版
使用 release 和 snapshot 仓库可以很容易达到以上要求。
稳定对外开放的版本,放到 release 仓库。版本不能覆盖,保证外部使用不受版本更新的影响。
迭代开发的不稳定版本,放到 snapshot 仓库。版本可覆盖,小伙伴测试的时候,不需要修改依赖的版本号,最多需要清除下 Maven 的依赖缓存,就可以下载到最新的版本。
上面提到的 目前 maven-releases 和 maven-snapshots 是 hosted 类型的仓库是 Nexus 默认创建的两个仓库,实际工作中,我们可以自定义创建仓库,自己规定为 release 库和 snapshot 库。下面给出两者的正确使用姿势,方便以后使用:
release库(发布库)使用规则及场景
场景:
release库是存放稳定版本包的仓库,线上发布的程序都应从release库中引用正确版本进行使用。
使用规则:
release库仓库名中带有“releases”标识,
release 库不允许删除版本;
release 库不允许同版本覆盖;
release库上传的jar包版本号(version)不能以“-SNAPSHOT”结束(版本号中的SNAPSHOT是release版和snapshot版区别的唯一标识);
第三方包(非公司内部开发)仅可引用 release 版
最好提供源码包 sources.jar 和方法文档 javadoc.jar,方便引用方使用。
snapshot库(快照库)使用规则及场景
场景:
snapshot库是存放中间版本包的仓库,代表该库中依赖包的程序处于不稳定状态。当代码在开发过程中有其他程序需要引用时,可以提供snapshot版用于调试和测试。由于snapshot库的包依然处于测试状态,所以随时可以上传同版本最新包来替换旧包,基于这种不稳定状态,maven允许snapshot库中的包被编译时随时更新最新版,这就可能会导致每次打包编译时同一个版本jar会包含不同的内容,所以snapshot库中的包是不能用来发布的;
使用规则:
snapshot 库仓库名中带有“snapshots”标识,
snapshot 库可以删除版本;
snapshot 库可以实现版本覆盖;
第三方包(非公司内部开发)不允许引用 snapshot 版
快照库上传的版本号(version)必须以“-SNAPSHOT”结束,并上传至私服后系统将自动将“-SNAPSHOT”替换为时间戳串(本地代码引用时依然用“-SNAPSHOT”结束的版本号,无需替换时间戳),一个快照包线上将存在至少两个版本。
是否允许版本覆盖
其中是否允许版本覆盖,是否可以删除版本,可以通过 Nexus Repository 设置:
拉取不到最新版本?
在 Gradle 引用 snapshot 库版本时,若遇到已经上传最新版本,但是好像没有作用时,不要惊慌,不要失措。请先到项目目录下,使用以下命令清理一下 gradle的缓存,再且试试:
//Windows
gradlew build --refresh-dependenciess
Gradle7.x之前
classpath 'com.android.tools.build:gradle:3.5.0'
distributionUrl=https\://services.gradle.org/distributions/gradle-6.3-all.zip
module
apply from: './nexus-push.gradle'
nexus-push.gradle
apply plugin: 'maven'
task androidSourcesJar(type: Jar) {
classifier = 'sources'
from android.sourceSets.main.java.srcDirs
}
artifacts {
archives androidSourcesJar
}
uploadArchives {
repositories {
mavenDeployer {
repository(url: "http://192.168.10.162:8081/nexus/content/repositories/releases/") {
authentication(userName: "admin", password: "admin123")
}
pom.groupId = 'com.hengda.util'
pom.artifactId = 'util'
pom.version = '0.0.1'
pom.project {
licenses {
license {
name 'The Apache Software License, Version 2.0'
url 'http://www.apache.org/licenses/LICENSE-2.0.txt'
}
}
}
}
}
}
artifacts 中可以指定要上传的 jar 或 aar 的路径
上传 gradlew clean uploadArchives
Gradle7.x之后
Android studio 更新到了 4.2,伴随着正式的JDK 11环境以及 Gradle 7.0,迎来了一系列的 gradle 编译问题,当然,这里主要讨论 maven 发布相关的变更与适配。
以前的 maven plugin 已经被废弃,带来的是 maven-publish plugin 。从代码层面讲就是:
apply plugin: 'maven'
变成了:
apply plugin: 'maven-publish'
同时,相关脚本也进行了变更
apply plugin: 'maven-publish'
publishing {
repositories {
maven {
allowInsecureProtocol true
credentials {
username 'admin' // 仓库发布用户名
password 'admin123' // 仓库发布用户密码
}
// url 'http://127.0.0.1:8081/repository/maven-releases/' // 仓库地址
url 'http://192.168.10.162:8081/nexus/content/repositories/releases/' // 仓库地址
}
}
publications {
maven(MavenPublication) {
groupId 'com.hengda.util' // groupId
artifactId 'util' // artifactId
version '1.0.0' // 发布版本
description '说明描述' // 说明描述
artifact("$buildDir/outputs/aar/${project.name}-release.aar")
}
}
}
注意
- 对于非 https 的仓库地址,需要使用
allowInsecureProtocol
字段,包括引用该仓库的地方
allowInsecureProtocol true
完整代码
apply plugin: 'maven-publish'
def GROUP_ID = 'com.hengda.util'
def ARTIFACT_ID = 'util'
def VERSION_NAME = '1.0.0'
def DESCRIPTION = '说明'
//仓库地址
//def MAVEN_URL = "http://127.0.0.1:8081/repository/maven-releases/"
def MAVEN_URL = "http://192.168.10.162:8081/nexus/content/repositories/releases/"
def nexusUsername = 'admin'
def nexusPassword = 'admin123'
task sourceJar(type: Jar) {
if (hasAndroidPlugin()) {
println "======> Android"
from android.sourceSets.main.java.srcDirs
//noinspection GroovyAccessibility
archiveClassifier = 'sources'
} else if (hasJavaPlugin()) {
println "======> Java"
from sourceSets.main.allSource
//noinspection GroovyAccessibility
archiveClassifier = 'sources'
}
}
afterEvaluate {
project ->
tasks.all {
Task task ->
if (task.name.equalsIgnoreCase('publishAarPomPublishPublicationToSnapshotsRepository')) {
task.dependsOn tasks.getByName('assemble')
}
}
}
def hasJavaPlugin() {
if (plugins.hasPlugin("java-library")) {
return true
}
return false
}
def hasAndroidPlugin() {
if (plugins.hasPlugin("com.android.library")) {
return true
}
return false
}
publishing {
println "======> ${project.name}"
println "====> the aar path is " + "$buildDir/outputs/aar/${project.name}-release.aar"
println "====>" + MAVEN_URL
println "====>" + VERSION_NAME
publications {
aarPomPublish(MavenPublication) {
groupId GROUP_ID
artifactId ARTIFACT_ID
version VERSION_NAME
description DESCRIPTION
artifact(sourceJar)
artifact("$buildDir/outputs/aar/${project.name}-release.aar")
}
}
repositories {
maven {
allowInsecureProtocol true
name "snapshots"
url MAVEN_URL
credentials {
username = nexusUsername
password = nexusPassword
}
}
}
}
artifact 区分jar
上传命令 gradlew publish
Nexus2与Nexus3
- 3.x对于jar的本地缓存不再是像2.x一样,直接保存单个jar包,而是采用Blob Stores保存,即一个jar被保存为单bytes文件。因此将没法使用:直接批量扔jar,再手动更新这种方式。
- 相比2.x,自带JAVA环境,安装方便
- 支持管理Docker
- 支持npm和bower的package管理
- 不能再像2.x一样,点击相关jar后含有出现,方便复制粘贴