3

Nexus私有maven库部署和使用 - Stars-one

 1 year ago
source link: https://www.cnblogs.com/stars-one/p/17047723.html
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

Nexus私有maven库部署和使用

本文为作者原创,允许转载,不过请在文章开头明显处注明链接和出处!!! 谢谢配合~
作者:stars-one
链接:https://www.cnblogs.com/stars-one/p/17047723.html

本篇大约有12003个字,阅读预计需要15.00分钟


原文地址:Nexus私有maven库部署和使用 - Stars-One的杂货小窝

前段圣诞节前后,Jitpack网站突然崩溃了,无法下载依赖,然后过了一个星期才解决了,好在没啥紧急的Android开发任务,没啥影响,但是也给我了一些提醒,可能搭建个私有库会比较保险,于是就是研究了私有库nexus的部署和使用

nexus私有库,支持npm,java,pythod等库的存放,支持的也比较全面,搭建起来也十分简单。

除此之外,还可以拿私有库当一个镜像中转站,比如说阿里云镜像,实际上它也是将一些中央仓库的库都下载保存下来了,以防中央仓库无法访问导致依赖无法下载的问题,有个缺点就是阿里云没有支持Jitpack这种小众网站

我们可以利用私有库,把Jitpack这种网站也加入进来,也提高了下载依赖的速度和环境的配置

1.下载运行

前往官方下载页下载安装文件,这里以window为例,下载了window的压缩包文件

1210268-20230104143354495-689725461.png

之后解压,得到两个文件夹目录

1210268-20230104143439421-214508245.png

打开sonatype-work\nexus3\etc\nexus.properties文件,修改端口号,如下图所示,我是修改为了9888端口(这里需要运行nexus之后,待其安装好相关环境之后才会有这个nexus.properties的文件)

1210268-20230104143559588-820620724.png

之后进入到nexus-3.45.0-01\bin命令下,打开cmd窗口,运行命令nexus.exe /run,即可将nexus运行起来了

运行起来后,我们访问localhost:9888即可进入到web页面

点击右上角的账号登录,提示我们可以在该路径找到用户名和密码

1210268-20230104143219571-833976503.png

账号名为admin,密码则是你用记事本打开那个admin.password文件里的内容

登录成功后会提示我们输入新密码来修改密码,照着走即可

1210268-20230104144231499-730041850.png

下一步需要设置是否公开库的选项,不公开的话,下载则需要设置账号和密码才能下载库,我这里就选择了不公开(第二个选项)

1210268-20230104144606935-1910150765.png

之后完成就可以使用了

1210268-20230104151651026-454497098.png

首先,先介绍说明的对应的仓库信息

  • maven-releases 发行版组件, hosted 类型
  • maven-snapshots:快照(调试版本)组件, hosted 类型
  • maven-central:maven 中央库,就是代理 https://repo1.maven.org/maven2/,proxy 类型
  • maven-public:仓库分组概念,虚拟的 把上面三个仓库合并形成一个组,方便引用, group 类型

配置maven依赖的时候,我们只需要引用maven-public的地址即可

而我们需要上传组件,可以上传到maven-releasesmaven-snapshots这两个仓库中即可

原理如下:

1210268-20230104151937672-1614458409.png

Maven中使用

1.手动上传jar包

进入到上传jar包的页面

1210268-20230104152036867-1869601664.png

选择一个jar文件进行上传

1210268-20230104152247157-410772617.png

然后上传成功,就可以查看到我们的jar包了

1210268-20230104152433835-2120541555.png

2.自动上传jar包

首先,需要maven的setting.xml文件中配置私服的账号和密码

<server>
  <id>myLocalRepo</id>
  <username>admin</username>
  <password>admin</password>
</server>

PS:注意外层还有个servers标签

之后根据你的需要,在项目里的pom.xmlsetting.xml中添加配置distributionManagement标签信息

项目里,则是单独配置;而setting.xml,则是全局配置的

这里我以项目里为例,在pom.xml中加上配置

 <distributionManagement>
        <repository>
            <id>myLocalRepo</id>
            <name>本地私有库</name>
            <url>http://localhost:9888/repository/maven-releases/</url>
        </repository>
<!--  配置快照版本的仓库上传地址,这里不演示了,自行修改      -->
<!--        <snapshotRepository>-->
<!--            <id>myLocalRepo</id>-->
<!--            <name>本地私有库</name>-->
<!--            <url>http://localhost:9888/repository/maven-snapshots/</url>-->
<!--        </snapshotRepository>-->
    </distributionManagement>

PS:外层还有个project标签,注意id要与上面的serve中的id一致!

这里如果你配置了snapshotRepository,当你当前的pom文件版本带有snapshot后缀,就会上传到snapshotRepository对应的仓库里

使用maven命令进行发布jar包,注意项目路径

mvn deploy

或者直接点右侧的maven菜单也可以进行

1210268-20230105152650626-1002930434.png

这里需要注意的是,如果你的pom文件里的版本是有snapshot结尾,发布后会jar包会出现在maven-snapshots仓库中

1.出现405错误

因为仓库用的不是host类型的,所以导致的错误,更换仓库地址即可解决问题

2.上传出现400问题

错误如下提示:

Failed to execute goal org.apache.maven.plugins:maven-deploy-plugin:2.7:deploy (default-deploy) on project mydemo: Failed to deploy artifacts: Could not transfer artifact site.starsone:mydemo:jar:1.0-20230105.091429-1 from/to myLocalRepo (http://localhost:9888/repository/maven-releases/): Transfer failed for http://localhost:9888/repository/maven-releases/site/starsone/mydemo/1.0-SNAPSHOT/mydemo-1.0-20230105.091429-1.jar 400 Repository version policy: RELEASE does not allow version: 1.0-20230105.091429-1

解决方案:

由于当前的pom里面的版本带有关键字snapshots,而上传的仓库只能接收release版本的,所以导致的错误

1210268-20230105172201574-1642128095.png
1210268-20230105172134697-793086026.png

将版本的snapshots关键字删除即可解决问题

3.重复发布版本失败

当你发布了一个1.0版本后,然后更改了代码,想重新发布1.0版本,会提示报错

Failed to execute goal org.apache.maven.plugins:maven-deploy-plugin:2.7:deploy (default-deploy) on project mydemo: Failed to deploy artifacts: Could not transfer artifact site.starsone:mydemo:jar:1.0 from/to myLocalRepo (http://localhost:9888/repository/maven-releases/): Transfer failed for http://localhost:9888/repository/maven-releases/site/starsone/mydemo/1.0/mydemo-1.0.jar 400 Repository does not allow updating assets: maven-releases

需要去该仓库里的设置进行以下配置:

1210268-20230105172624547-29239383.png

4.打包后出现boot-inf文件夹

如果项目中有maven-plugin插件的话,需要配置skip属性为true,否则会出现打包之后出现BOOT-INF,导致引入依赖时没法使用

1210268-20230105172759019-1991212025.png

Gradle中使用

Gradle主要是以上传Android的aar包为例,如果是普通jar包,可以参考官方文档

使用maven-publish'插件:

Gradle7.0版本之后都必须使用这个了,但此插件也支持旧版本的Gradle来使用

单Module发布

这里,假设我们只有一个module,如下图目录所示:

1210268-20230112184246928-276576723.png

有一个auth的库需要进行发布,我们想要将此库发布在本地私有库中,则需要对其的build.gradle进行更改,如下面代码(省略了android闭包等部分:

plugins {
    id 'com.android.library'
    id 'maven-publish'
}

//定义你的私有库地址和密码
def NEXUS_MAVEN_URL = "http://localhost:9888/repository/maven-releases/"
def NEXUS_USERNAME = "admin"
def NEXUS_PASSWORD = "admin"

//对饮的依赖坐标和描述
def POM_NAME = "webviewbase"
def POM_GROUP_ID = "site.starsone"
def POM_ARTIFACT_ID = "webviewbase"
def POM_VERSION = "1.5"
def POM_PACKAGING = "aar"
def POM_DESCRIPTION = "webviewbase基础库"

afterEvaluate {
    publishing {
        publications {
            aar_pub(MavenPublication) {

                //定义group和版本
                group = POM_GROUP_ID
                //定义构造物id
                artifactId = POM_ARTIFACT_ID
                version = POM_VERSION

                pom {
                    name = POM_NAME
                    description = POM_DESCRIPTION
                    url = 'http://www.example.com/library'
                    //类型设置为aar
                    packaging = POM_PACKAGING

                    licenses {
                        license {
                            name = 'The Apache License, Version 2.0'
                            url = 'http://www.apache.org/licenses/LICENSE-2.0.txt'
                        }
                    }
                    developers {
                        developer {
                            id = 'starsone'
                            name = 'stars-one'
                            email = '[email protected]'
                        }
                    }
                }
                //带上依赖 ,否则会报错
                pom.withXml {
                    def dependenciesNode = asNode().appendNode('dependencies')
                
                    def scopes = [configurations.compile]
                    if (configurations.hasProperty("api")) {
                        scopes.add(configurations.api)
                    }
                    if (configurations.hasProperty("implementation")) {
                        scopes.add(configurations.implementation)
                    }
                    if (configurations.hasProperty("debugImplementation")) {
                        scopes.add(configurations.debugImplementation)
                    }
                    if (configurations.hasProperty("releaseImplementation")) {
                        scopes.add(configurations.releaseImplementation)
                    }
                
                    scopes.each { scope ->
                        scope.allDependencies.each {
                            if (it instanceof ModuleDependency) {
                                boolean isTransitive = ((ModuleDependency) it).transitive
                                if (!isTransitive) {
                                    println "<<<< not transitive dependency: [${it.group}, ${it.name}, ${it.version}]"
                                    return
                                }
                            }
                
                            if (it.group == "${project.rootProject.name}.libs" || it.version == 'unspecified') {
                                return
                            }
                
                            if (it.group && it.name && it.version) {
                                def dependencyNode = dependenciesNode.appendNode('dependency')
                                dependencyNode.appendNode('groupId', it.group)
                                dependencyNode.appendNode('artifactId', it.name)
                                dependencyNode.appendNode('version', it.version)
                                dependencyNode.appendNode('scope', scope.name)
                            }
                        }
                    }
                }
                
                artifact("$buildDir/outputs/aar/${project.getName()}-release.aar")
            }
        }
        repositories {
            maven {
                //设置仓库地址和账号密码
                url = NEXUS_MAVEN_URL
                credentials {
                    username = NEXUS_USERNAME
                    password = NEXUS_PASSWORD
                }
                //下面是动态切换release仓库或snapshot仓库
//            def releasesRepoUrl = "$buildDir/repos/releases"
//            def snapshotsRepoUrl = "$buildDir/repos/snapshots"
//            url = version.endsWith('SNAPSHOT') ? snapshotsRepoUrl : releasesRepoUrl
            }
        }
    }
}

编写了上述的脚本代码后,及得resync一下仙姑,之后从右侧的Gradle菜单进入到你的模块下,展开task目录,可以找到发布的命令,如下图所示

1210268-20230112184918749-255296680.png

这里发布的话,步骤有4个:

  1. 修改版本号(上述脚本里的POM_VERSION字段)
  2. 执行clean命令
  3. 执行编译命令
  4. 执行发布命令

具体步骤如下图所示:

1210268-20230112185205760-2051564852.png
1210268-20230106175620944-1398051354.png
1210268-20230112184918749-255296680.png

gradle如何依赖私有库的话,请看下面的章节说明

多Module发布

如果我们是想要发布多个Module,如果采用上述的方法,就是得在每个Module里都加上脚本,十分繁琐。

研究了下,想实现Jitpack那种可以一键发布所有Module的方法,最终还是不成功,于是就采用了一种稍微折中的方法,就是创建一个公共的gradle脚本,用来发布aar,然后所有的Module去引用此脚本即可,虽然也要对每个Module进行修改,但也算是比较折中的方法了,图省事的话可以用替换功能进行脚本的添加

公共脚本nexus-maven-publish.gradle,放在了项目的根目录,与setting.gradle同级别,脚本代码如下:

apply plugin: 'maven-publish'

def NEXUS_MAVEN_URL = "http://localhost:9888/repository/maven-releases/"
def NEXUS_USERNAME = "admin"
def NEXUS_PASSWORD = "admin"

//与jitpack发布的保持同个组织名
def POM_GROUP_ID = "com.github.TYKYTeam.swan-android-libray"
//版本好
def POM_VERSION = "2.1"
//aar包方式
def POM_PACKAGING = "aar"
//下面三个数值自动读取模块名
def POM_NAME = ""
def POM_ARTIFACT_ID = ""
def POM_DESCRIPTION = ""

def depList = parent.getDependencies()
depList.getModules().each {
    println "数据。。" + this.name
    POM_ARTIFACT_ID = this.name
    POM_NAME = this.name
}

afterEvaluate {
    publishing {
        publications {
            aar_pub(MavenPublication) {

                //定义group和版本
                group = POM_GROUP_ID
                //定义构造物id
                artifactId = POM_ARTIFACT_ID
                version = POM_VERSION

//            artifact androidSourcesJar//将源码打包进aar,如果不需要可以去掉
//            artifact androidJavadocsJar//将注释打包进aar,如果不需要可以去掉
                artifact("$buildDir/outputs/aar/${project.getName()}-release.aar")

                pom {
                    name = POM_NAME
                    description = POM_DESCRIPTION
                    url = 'http://www.example.com/library'
                    //类型设置为aar
                    packaging = POM_PACKAGING

                    licenses {
                        license {
                            name = 'The Apache License, Version 2.0'
                            url = 'http://www.apache.org/licenses/LICENSE-2.0.txt'
                        }
                    }
                    developers {
                        developer {
                            id = 'com'
                            name = 'stars-one'
                            email = '[email protected]'
                        }
                    }
                }

                //带上依赖 ,否则会报错
                pom.withXml {
                    def dependenciesNode = asNode().appendNode('dependencies')

                    def scopes = [configurations.compile]
                    if (configurations.hasProperty("api")) {
                        scopes.add(configurations.api)
                    }
                    if (configurations.hasProperty("implementation")) {
                        scopes.add(configurations.implementation)
                    }
                    if (configurations.hasProperty("debugImplementation")) {
                        scopes.add(configurations.debugImplementation)
                    }
                    if (configurations.hasProperty("releaseImplementation")) {
                        scopes.add(configurations.releaseImplementation)
                    }

                    scopes.each { scope ->
                        scope.allDependencies.each {
                            if (it instanceof ModuleDependency) {
                                boolean isTransitive = ((ModuleDependency) it).transitive
                                if (!isTransitive) {
                                    println "<<<< not transitive dependency: [${it.group}, ${it.name}, ${it.version}]"
                                    return
                                }
                            }

                            if (it.group == "${project.rootProject.name}.libs" || it.version == 'unspecified') {
                                return
                            }

                            if (it.group && it.name && it.version) {
                                def dependencyNode = dependenciesNode.appendNode('dependency')
                                dependencyNode.appendNode('groupId', it.group)
                                dependencyNode.appendNode('artifactId', it.name)
                                dependencyNode.appendNode('version', it.version)
                                dependencyNode.appendNode('scope', scope.name)
                            }
                        }
                    }
                }
            }

        }

        repositories {
            maven {
                //设置仓库地址和账号密码
                url = NEXUS_MAVEN_URL
                credentials {
                    username = NEXUS_USERNAME
                    password = NEXUS_PASSWORD
                }
                //下面是动态切换release仓库或snapshot仓库
//            def releasesRepoUrl = "$buildDir/repos/releases"
//            def snapshotsRepoUrl = "$buildDir/repos/snapshots"
//            url = version.endsWith('SNAPSHOT') ? snapshotsRepoUrl : releasesRepoUrl
            }
        }
    }
}

在Module里build.gradle文件里进行引用:

buildscript {
    apply from: "../nexus-maven-publish.gradle"
}

plugins {
    id 'com.android.library'
    id 'com.github.dcendents.android-maven'
}
//后面的省略...

PS:buildscript要放在plugins之前

发布aar的步骤:

1.修改nexus-maven-publish.gradle文件里定义的版本号POM_VERSION

注意下面的步骤执行的命令不是单个Module里的哦!!

2.清除数据和重新编译

1210268-20230112111331471-1211024599.png

3.发布(注意和上面的单Module有所不同)

1210268-20230112104631659-1485893100.png

本来想着自定义一个Task,实现上面的各命令的点击操作的,不然每次发布都要点个几次鼠标可太累了,但最终还是实现不了,如果有大佬路过可以在评论区指点一下,感激不尽

使用maven插件:

plugins {
    id 'com.android.library'
    id 'publishing'
    id 'maven'
}

def NEXUS_MAVEN_URL = "http://localhost:9888/repository/maven-releases/"
def NEXUS_USERNAME = "admin"
def NEXUS_PASSWORD = "admin"

def POM_NAME = "webviewbase"
def POM_GROUP_ID = "site.starsone"
def POM_ARTIFACT_ID = "webviewbase"
def POM_VERSION = "1.0"
def POM_PACKAGING = "aar"
def POM_DESCRIPTION = "webviewbase基础库"
uploadArchives {
    configuration = configurations.archives
    repositories {

        mavenDeployer {
            repository(url: NEXUS_MAVEN_URL) {
                authentication(userName: NEXUS_USERNAME, password: NEXUS_PASSWORD)
            }
//                snapshotRepository(url: NEXUS_MAVEN_SNAPSHOT_URL) {
//                    authentication(userName: NEXUS_USERNAME, password: NEXUS_PASSWORD)
//                }
            //'groupId:artifactId:version' 或 'groudId:artifactId:version@aar' 形式
            pom.project {
                name POM_NAME
                groupId POM_GROUP_ID
                artifactId POM_ARTIFACT_ID
                version POM_VERSION
                packaging POM_PACKAGING
                description POM_DESCRIPTION
            }
        }
    }
}
// 生成sources.jar  写 artifacts {} 之前
task androidSourcesJar(type: Jar) {
    classifier = 'sources'
    from android.sourceSets.main.java.srcDirs
}
artifacts {
    //编译的源码类型
    archives androidSourcesJar
    //archives androidJavadocsJar
}

android{
    ...
}

通过右侧的gradle菜单可以触发上传

1210268-20230106180001302-838242692.png

依赖本地私有库(Maven)

步骤稍微有些繁琐,需要修改maven目录下的setting.xml文件,不过改一次就好

1.serve配置

首先声明一下私有库的账号密码

注意这里的id是随意定义的,可以自由编写,但需要与下面的profile里的id对应

<server>
  <id>localRepo</id>
  <username>admin</username>
  <password>admin</password>
</server>

这里看网上的介绍说,只是打包上传的时候maven会读取这里,实际上,如果私有库没有开放允许任何人访问(即我上面部署操作的步骤),到时候依赖的时候也会去根据id去读取这个server标签,否则到时候也是无法依赖的

2.profile配置

网上看其他资料,是去加了mirror,但实际上:

如果mirrors下即使有多个mirror配置,实际上只会去第一个mirror里找,找不到不会往下个mirror里找的

除非第一个mirror因为网络原因链接不上,才会触发到下一个mirror里去找依赖的操作逻辑

<profile>

  <id>localRepoProfile</id>

  <activation>
    <jdk>1.8</jdk>
  </activation>

  <repositories>
    <repository>
      <id>localRepo</id>
      <name>本地私有库</name>
        <url>http://localhost:9888/repository/maven-public/</url>
      <layout>default</layout>
      <snapshotPolicy>always</snapshotPolicy>
    </repository>
  </repositories>
</profile>

3.激活配置

<activeProfiles>
    <activeProfile>localRepoProfile</activeProfile>
</activeProfiles>

之后在pom.xml里输入本地私有库里的依赖坐标即可正常依赖

补充-单独设置项目使用私有库

上面的2和3步骤,是在全局的maven中进行配置的个更改,而还有可以单独为某个项目去配置的,直接去修改pom.xml文件即可,如下面例子:

<project>
...
    <repositories>
        <repository>
            <id>localRepo</id>
            <name>本地私有库</name>
            <url>http://localhost:9888/repository/maven-public/</url>
        </repository>
    </repositories>
</project>

依赖本地私有库(Gradle)

如果私有库是开了账号限制,可以在依赖的仓库源中设置账号和密码

maven{
    url 'http://xxxx:8082/artifactory/android_group'
    //下面这是账号和密码
    credentials{
        username=""
        password = ""
    }
}

About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK