【Gradle】(三)详细聊聊依赖管理:坐标、依赖配置、依赖传递、依赖冲突
文章目录
- 1.概述
- 2.依赖管理
- 2.1.坐标
- 2.2.依赖的基本概念
- 2.3.依赖配置(Dependency configurations)
- 2.3.1.依赖路径
- 2.3.2.依赖配置与依赖路径的关联
- 2.4.依赖传递
- 2.4.1.准备工作
- 2.4.2.运行时依赖传递
- jar包生成与依赖配置
- 依赖树打印
- 使用 Dependency Analyzer 查看依赖
- 2.4.3.编译时依赖传递
- 2.5.依赖冲突
- 2.5.1.依赖解析(dependency resolution)
- 版本号的组成
- 版本号排序规则
- 2.5.2.排除传递依赖
- 单个排除
- 全局排除
- 2.5.3.强制指定版本号
- 3.总结
1.概述
在前面两篇文章中,我们已通过 Gradle 创建了一个多模块的项目,并介绍了一些常用的核心概念。至此,我们已能够在工作中使用 Gradle 了。
本篇内容主要讲解 Gradle 的依赖管理,旨在让大家对 Gradle 的依赖特性有一定了解,能够处理工作中出现的一系列依赖冲突问题,包含以下内容:
- 讲解坐标的概念
- 介绍依赖范围的概念及选择
- 说明依赖如何传递、如何避免依赖传递
- 阐述依赖冲突的概念、如何确认依赖冲突、如何解决依赖冲突
Gradle历史文章:
《【Gradle】(一)在IDEA中初始化gradle项目及其核心概念解释》
《【Gradle】(二)多模块项目、api推送到Maven私服、及SpringBoot可执行Jar包》
Maven相关文章:
《Maven中的依赖功能特性》
《Maven坐标的概念与规则》
对Maven感兴趣的话,可以看看我的上面两篇Maven文章,里面也介绍了一些依赖的概念,当然,如果不感兴趣的话,本篇文章也会引用这两篇Maven中的部分内容,不影响本篇文章的阅读。
2.依赖管理
2.1.坐标
在 Gradle 中,依赖的版本控制通常基于 Maven 的坐标系统,使用组 ID(groupId)、构件 ID(artifactId)和版本号(version)来唯一标识一个依赖项,这被称为 GAV(坐标)。
例如:implementation "cn.hutool:hutool-all:5.8.18"
,其中 cn.hutool
是组 ID,hutol-all
是构件 ID,5.8.18
是版本号。
Gradle的构建一般也是使用的Maven仓库,很多时候在仓库中的jar包是共用的,所以我们在编写坐标时,也应遵循Maven的规范:
groupId
:指的是当前构建隶属的实际项目,一般是 公司的网址倒序 + 项目名artifactId
:一般是指的当前项目中的其中一个模块version
:当前项目的版本号
版本号也不是随便写的,在业界有通用的规则,定义方式如下:
{主版本号}.{次版本号}.{增量版本号}-{里程碑版本}
- 主版本号:一般是指的当前的项目有了重大的架构变动,版本之间几乎完全不兼容,例如:最近出的 SpringBoot3 就已经放弃了Java8,如果不升级 JDK的话,还是只能使用SpringBoot2
- 次版本号:一般是指的项目的迭代版本,这种版本会修复大量的bug,带来一些小的新特性等,但是没有什么架构上的重大变化。
- 增量版本号:一般是用于修复一些紧急bug,改动量很小时,可以使用增量版本号。
- 里程碑版本:就是项目的当前版本处于一个什么样的阶段了,常见的里程碑版本有
SNAPSHOT
,alpha
,beta
,release
,GA
等。
在里程碑的版本中,标注SNAPSHOT
的为开发版,此时会存在大量的代码变动,alpha
和beta
分别对应的是内测版与公测版这三个版本都是属于不稳定版本,使用的时候非常容易踩坑,所以一般只用的demo体验,在正式环境中不能使用。
release
和GA
都属于是稳定的正式版本,可以在正式环境中使用。
下面是SpringBoot的一些版本号,可以体验一下:
2.2.依赖的基本概念
在软件开发中,依赖是指一个项目或模块对其他项目或模块的需求。例如,如果一个项目需要使用某个第三方库来实现某些功能,那么这个项目就对该第三方库存在依赖。
假设现在有 A、B、C 三个构件,如下图中表示的就是A依赖B和C
通过坐标定义:
dependencies {implementation "com.ls:B:1.0.0"implementation "com.ls:C:1.0.0"
}
2.3.依赖配置(Dependency configurations)
在这个章节会了解到Gradle中的几种常用的依赖路径,以及依赖配置和依赖范围的对应关系《官方参考文档》
2.3.1.依赖路径
从宏观的角度来看,常用的依赖类型有两种:编译路径(CompileClasspath)和运行时路径(RuntimeClasspath),在这两个概念的基础上,又加入了测试代码和非测试代码的区分,概念如下:
CompileClasspath
:编译类路径,在编译项目时需要的依赖路径。RuntimeClasspath
:运行时类路径,在运行项目时需要的依赖路径。TestCompileClasspath
:测试代码编译类路径,是在编译测试代码时所需的依赖路径。TestRuntimeClasspath
:测试代码运行时类路径,用于运行测试代码时所需的依赖路径。
除此之外,还有一种特殊的路径annotationProcessor
,它也是一种依赖配置,在编译时生效。主要是用于将某些注解添加到依赖路径中,启用对注解的支持。在上篇文章中提到的lombok
的注解支持就是这种类型:
dependencies {compileOnly "org.projectlombok:lombok:$lombokVersion"annotationProcessor "org.projectlombok:lombok:$lombokVersion"
}
说的更直白一点,所谓的编译时路径,就是写代码的时候可以直接Import使用的路径,运行时路径就是写代码的时候无法引入,但在程序运行的时候能够访问到(常见于间接依赖中)。
2.3.2.依赖配置与依赖路径的关联
- implementation:添加直接依赖包到编译时和运行时环境
- api:添加直接依赖包和间接依赖包到编译时和运行时环境,即向上层传递内部依赖关系
- compileOnly:添加依赖包,不添加到运行时路径
- runtimeOnly :不添加到编译时路径,添加运行时路径
- annotationProcessor:添加到注解处理器的类路径,不添加到运行时路径
更多依赖配置对应的依赖路径关系如下表所示:
依赖配置 | Compile Classpath | Runtime Classpath |
---|---|---|
api | √ | √ |
implementation | √ | √ |
compileOnlyApi | √ | × |
compileOnly | √ | × |
runtimeOnly | × | √ |
testImplementation | √ | √ |
testCompileOnly | √ | × |
testRuntimeOnly | × | √ |
annotationProcessor | √ | × |
在上面的表格中,有test
前缀的依赖配置,只会在test
任务中生效。
此外,可以看到还多了一个api
,这也是一个可能会使用到的功能,主要是用在依赖传递中,在下面会讲解。
2.4.依赖传递
我们上面提到了编译时和运行时两种依赖路径,依赖传递也分为编译时依赖传递和运行时依赖传递,其中编译时依赖传递还依赖于api
这个依赖配置,要使用这个配置,还需要额外引入java-library
插件。下面就通过一个demo案例来体验一下两种依赖传递,同时,会介绍IDEA中自带的一种依赖查看工具 Dependency Analyzer。
2.4.1.准备工作
需要创建3个子模块进行模拟,分别是a-demo
,b-demo
,c-demo
,同时需要将它们打包到本地Maven仓库中。
创建子模块:
创建3个子模块,并修改每个子模块的build.gradle,里面只放入version = 1.0.0
,其他配置由根项目进行配置。
根项目配置
根项目中需要配置的有三个,插件配置、仓库配置、发布配置,配置的含义在本系列的前两篇文章中已经讲过了,这里就不再赘述了,根项目完整的配置如下,
plugins {id 'java'id 'org.springframework.boot' version "$springBootVersion" apply falseid 'io.spring.dependency-management' version "$springDenpendencyVersion" apply false
}allprojects {repositories {mavenLocal()maven {url 'https://maven.aliyun.com/repository/public'}mavenCentral()}
}subprojects {apply plugin: 'java'apply plugin: 'maven-publish'apply plugin: 'java-library'sourceCompatibility = JavaVersion.VERSION_1_8java {withSourcesJar()}publishing {publications {demo(MavenPublication) {from components.java}}repositories {maven {name = "mavenNexus"allowInsecureProtocol = truedef releasesRepoUrl = 'http://192.168.200.101:8081/repository/maven-releases/'def snapshotsRepoUrl = 'http://192.168.200.101:8081/repository/maven-snapshots/'url = version.endsWith('SNAPSHOT') ? snapshotsRepoUrl : releasesRepoUrlcredentials {username 'admin'password 'admin123'}}}}dependencies {compileOnly "org.projectlombok:lombok:$lombokVersion"annotationProcessor "org.projectlombok:lombok:$lombokVersion"}}
gradle.properties配置
资源文件中需要配置项目整体的groupId和默认的version。
group=com.ls
version=1.0.0
2.4.2.运行时依赖传递
jar包生成与依赖配置
要感受到依赖传递,需要依次对c-demo
,b-demo
两个依赖打包,首先是对c进行打包和推送到本地Maven仓库。
推送完成后修改b-demo
的build文件,再按同样的方式打包:
最后,在a-demo
中引入b-demo
,并刷新Gradle引用。
依赖树打印
这里有两种方式可以查看依赖关系,一种是gradle
自带的依赖树打印功能gradlew dependencies
,另一种则是使用IDEA中的 Dependency Analyzer工具。
我们先看看第一种方式,要看a-demo
的依赖关系,首先打开终端控制台,进入a-demo
模块,然后再利用根目录的gradlew
文件执行打印依赖树指令:
cd a-demo
../gradlew dependencies
在上图中,我们可以看到编译时路径和运行时路径 的依赖关系。
- 编译时路径中:
有b-demo
和lombok
,其中 b-demo 的依赖配置是implementation
,上面提到了,这种依赖配置会将jar包添加到编译时和运行时两种依赖路径中,lombok
是在根项目中配置的compileOnly
,每个子模块都继承了这个配置,所以可以看到在编译时路径中会存在,也正是因为在编译时存在,在代码中才可以直接使用。
可以看到的是,目前的配置中,编译时并没有发生依赖传递(即没有出现间接依赖)。 - 运行时路径中:
我们可以看到的是,在运行时路径中除了b-demo
这个直接依赖以外,还有c-demo
这个间接依赖,这是因为implementation
可以实现包在运行时路径上传递。
使用 Dependency Analyzer 查看依赖
如果觉得上面这种打印依赖树的方式有点繁琐,还可以使用IDEA的自带工具(好像是2022以上版本就有了)。如下图,可以直观的看到编译时和运行时的依赖关系,和上面打印出的结果是一致的。
如果想看到更详细的信息,可以选择红框中的任意一个包,右键选择Analyze Dependencies
进入到工具弹窗中。
通过这里的一系列操作就可以查看到自己想看的依赖关系了,举个例子:假如我现在想看a-demo
的运行时依赖关系,通过树状展示,可以这么做。
2.4.3.编译时依赖传递
编译时依赖传递需要通过api
这个依赖配置实现,通过java-library
插件引入。在根项目的subprojects
中已经设置了apply plugin: 'java-library'
,这里可以直接使用。
现在我希望将b-demo
中引入的c-demo
包,在编译时和运行时都通过,通过间接依赖的形式传递给a-demo
,只需要修改B模块中的build文件,将 implementation 修改为 api
,修改完成后重新打包。在a-demo
里面引入b。
- b-demo:
version = '1.0.1'dependencies {api 'com.ls:c-demo:1.0.0' }
- a-demo:
version = '1.0.0'dependencies {implementation 'com.ls:b-demo:1.0.1' }
最后的结果是,两种路径的依赖都传递了:
2.5.依赖冲突
简单的说,依赖冲突就是在一个项目中引入了 groupId 和 ArtifactId 一样,但 version 不一样的jar包,程序在使用时不能确定要使用哪一个包。
《依赖解析官网文档》
2.5.1.依赖解析(dependency resolution)
不管是Maven还是Gradle都有处理依赖冲突的“调解机制”,在Gradle中叫“依赖解析(dependency resolution)”机制,两者之间还是有一定的区别,在工作中需要注意,不能混为一谈。
- Maven的处理方式是通过“就近原则”,即选择依赖路径中最近的那个版本,详情可以看这篇文章《Maven坐标的概念与规则》
- Gradle使用的是“最新版本优先”策略,在有多个版本冲突时,Gradle 默认选择最高的版本。
在判断多个版本的高低时,是通过定义好的版本排序机制来处理的,如果想对这个排序机制有比较详细的了解,可以去看看《版本排序官方文档》,下面先聊一下版本号的组成规则,再解释一下这个排序机制。
版本号的组成
版本号实际上是由两部分组成的:BaseVersion
+Qualifier
。
- BaseVersion:基础版本号,规范的情况下由
x.y.z
3个数字组成,但也有其他字母组成的情况。 - Qualifier:限定符,规范的情况下有
beta
,SNAPSHOT
,RELEASE
,GA
等,也可能是其他不规则的符号,或者没有限定符。
下面的官网提供的例子,如何分解基础版本号与限定符:
在版本号里面有.
,+
,-
,_
这样的分隔符,以及字母和数字之间有一个空串
分隔符,出现这些分隔符的时候会找第一个不是.
的分隔符,左侧就是基础版本号,右侧就是限定符。
版本号排序规则
- 第一步:通过分隔符将版本号拆分成不同的组成部分
通过.
,+
,-
,_
这几个符号进行拆分,同时,如果有字母和数字的组合,也会拆解成不同的部分。
例如:1a1
,1.a.1
,1-a-1
不管分隔符是什么,都会拆分成[1,a,1]
三个部分。 - 第二步:分别对比每个部分的值
就像字符串的对比那样,从左到右,一个一个的对比,其大小规则为:2 > 1 > 0 > b > a > B > A
m遇到多个部分组合比较的时候,还要注意一个规则:1.1.0 > 1.1 > 1.1.a
- 第三步:特殊含义的限定符比较
比较规范的版本号中,右侧的限定符一般是用来标识当前的jar包状态的,例如是开发状态,还是发布状态,是测试版,还是稳定版等等。
这种情况也有优先级顺序:1.0-dev < 1.0-alpha < 1.0-zeta < 1.0-rc < 1.0-snapshot < 1.0-final < 1.0-ga < 1.0-release < 1.0-sp < 1.0
上面的规则比较多,不太方便记忆,但是也没关系,在大多数情况下版本号都是比较规范的,只需要比较数字的大小就可以了。
2.5.2.排除传递依赖
我们在引入多种三方jar包的时候,通过依赖传递的特性,可能会间接引入了某一个jar包的多个版本,但我们并不想使用Gradle自动指定的最高版本,这时候我们就可以通过排除传递依赖的方式,把最高版本的包排除掉。《排除传递依赖官方文档》
单个排除
语法也比较简单,在implementation
引入依赖的时候,通过exclue
排除依赖就可以了(需要将语法由空格隔开,调整为用小括号包裹)。exclue
的参数常用的有4种组合,分别对应不同的功能:
-
排除所有传递依赖
artifactId
在exclue
的参数中使用module
标记。implementation("com.ls:demo-api:1.0.0") {exclude(group: '*') }implementation("com.ls:demo-api:1.0.0") {exclude(module: '*') }
-
指定排除某个
groupId
的依赖implementation("com.ls:demo-api:1.0.0") {exclude(group: 'org.slf4j') }
-
指定排除某个构件
implementation("com.ls:demo-api:1.0.0") {exclude(module: 'log4j') }
-
指定排除某个
groupId
下的某个构件依赖implementation("com.ls:demo-api:1.0.0") {exclude group: 'com.ls', module: 'c-demo' }
全局排除
除了一个一个的排除以外,有时候我们还想一次排除项目中的所有指定的传递依赖,例如前两年的log4j
包出现了安全问题,需要把它从全局排除掉。
以上面多个子模块的demo项目为例,先查依赖找到log4j
包:
// 根项目的 build.gradle 文件
subprojects {configurations.configureEach {exclude group: 'org.apache.logging.log4j', module: 'log4j-to-slf4j'exclude group: 'org.apache.logging.log4j', module: 'log4j-api'}
}
说明:configurations.configureEach
表示在所有的依赖配置中都排除掉,是Gradle6以后得功能,旧版本里面可以使用configurations.all
,排除后的结果如下图。
如果只想排除一定的依赖配置,可以通过下面的语法来实现:
// 根项目的 build.gradle 文件
subprojects {configurations {compileOnly.exclude group: 'org.apache.logging.log4j', module: 'log4j-to-slf4j'implementation.exclude group: 'org.apache.logging.log4j', module: 'log4j-api'}
}
2.5.3.强制指定版本号
可以通过force
来强制使用某个版本号,这个功能也是在configurations
中进行配置,平时使用的不多,这里就简单提一下:
configurations.all {resolutionStrategy {force 'com.ls:c-demo:1.0.1'}
}
指定了之后,就不会管依赖传递中c-demo
的版本号了,通通使用1.0.1版本。
3.总结
本文着重针对 Gradle 的依赖管理展开了全方位且极为详尽的介绍。在此过程中,清晰明确地提及了诸如坐标、依赖的基础概念、依赖配置、依赖传递还有依赖冲突等相关特性。在充分熟知并掌握了这些特性之后,于后续开展的工作当中,就能够更加精确、细致地对依赖进行管理,并且可以妥善、有效地处理由依赖冲突所引发的各种各样的问题。
相关文章:

【Gradle】(三)详细聊聊依赖管理:坐标、依赖配置、依赖传递、依赖冲突
文章目录 1.概述2.依赖管理2.1.坐标2.2.依赖的基本概念2.3.依赖配置(Dependency configurations)2.3.1.依赖路径2.3.2.依赖配置与依赖路径的关联 2.4.依赖传递2.4.1.准备工作2.4.2.运行时依赖传递jar包生成与依赖配置依赖树打印使用 Dependency Analyzer…...
C#数据类型:object、var和dynamic的比较与应用
在C#中,object、var和dynamic虽然常被提及为可以处理多种数据类型的“万能”方式,但它们各自有不同的应用场景、特性和优缺点。下面我将用通俗易懂的方式结合示例来详细说明这三者的区别与应用。 1. object 定义与应用场景:object是C#中所有…...
【面试题】MySQL(第一篇)
1. MySQL是什么? MySQL是一种开源的关系型数据库管理系统(RDBMS),它使用结构化查询语言(SQL)进行数据管理。MySQL具有高性能、可靠性、可扩展性和兼容性等特点,广泛应用于Web应用开发中。 2. …...
SQL Server集成服务(SSIS):数据集成的瑞士军刀
SQL Server集成服务(SSIS):数据集成的瑞士军刀 在数据仓库和大数据处理领域,SQL Server集成服务(SSIS)扮演着至关重要的角色。作为微软SQL Server套件的一部分,SSIS提供了一套强大的工具&#…...

鸿蒙开发HarmonyOS NEXT (三) 熟悉ArkTs (上)
一、自定义组件 1、自定义组件 自定义组件,最基础的结构如下: Component struct Header {build() {} } 提取头部标题部分的代码,写成自定义组件。 1、新建ArkTs文件,把Header内容写好。 2、在需要用到的地方,导入…...

值传递与引用传递:理解Java中的参数传递机制
值传递与引用传递:理解Java中的参数传递机制 1、值传递(Call by Value)2、引用传递(Call by Reference)3、总结 💖The Begin💖点点关注,收藏不迷路💖 值传递和引用传递的…...

Qt常用基础控件总结—带边框的部件(QFrame和QLabel)
带边框的部件 框架控件QFrame类 QFrame类介绍 QFrame 类是带有边框的部件的基类,带边框部件的特点是有一个明显的边框,QFrame类就是用来实现边框的不同效果的(把这种效果称为边框样式),所有继承自 QFrame 的子类都可以使用 QFrame 类实现的效果。 部件通常是矩形的(其他…...

太多项会毁了回归
「AI秘籍」系列课程: 人工智能应用数学基础 人工智能Python基础 人工智能基础核心知识 人工智能BI核心知识 人工智能CV核心知识 多项式回归的过度拟合及其避免方法 通过添加现有特征的幂,多项式回归可以帮助你充分利用数据集。它允许我们甚至使用简…...
python的魔法方法
python类中的self是什么? 对象的方法都会有一个self参数,类比于c,self就相当于c的this指针。 由一个类可以生成无数个对象,当一个对象的方法被调用时,对象会讲自身的引用作为第一个参数传给该方法,那么pyt…...
[Vue3 + TS + Vite] 获取网页选中内容的字符串格式或HTML格式
获取网页选中内容的字符串格式 let selected_text_by_mouse: any// 获取选中的文字 const mouse_selected_text(event:MouseEvent)>{const selection window.getSelection();if(selection && selection.rangeCount > 0){const content selection.toString();s…...

线程安全的原因及解决方法
什么是线程安全问题 线程安全问题指的是在多线程编程环境中,由于多个线程共享数据或资源,并且这些线程对共享数据或资源的访问和操作没有正确地同步,导致数据的不一致、脏读、不可重复读、幻读等问题。线程安全问题的出现,通常是…...

微信零钱明细删除了还能恢复吗?图文教程解析
在日常使用微信支付的过程中,查看零钱明细是管理个人财务的一项重要操作。然而,有时候我们可能会不小心删除了这些明细,导致无法追踪资金流动和消费记录。那么,微信零钱明细删除了还能恢复吗?这是许多用户关心的问题。…...

mp4视频太大怎么压缩不影响画质,mp4文件太大怎么变小且清晰度高
在数字化时代,我们常常面临视频文件过大的问题。尤其是mp4格式的视频,文件大小往往令人望而却步。那么,如何在不影响画质的前提下,有效地压缩mp4视频呢?本文将为您揭秘几种简单实用的压缩技巧。 在分享和存储视频时&am…...

【线程同步-2】
同步方法及同步块 接上期三大不安全案例,本期将介绍同步方法和同步块,以期达到安全的目的。 车站买票:加入了synchronized 同步方法 package syn; //不安全的买票 //线程不安全,有负数 public class UnsafeBuyTicket {publi…...

【别再为可视化工具付费了!】财务报表免费制作软件,这款免费可视化工具的功能超乎想象
会计工作中,关键一步就是把那些繁杂的财务数据整理成清晰易懂的财务报表,这就像是把一堆拼图块变成一幅完整的图画。山海鲸可视化这款免费工具,支持实时数据刷新,能够随时随地更新你的财务数据,确保你拿到的永远是最新…...

【HTML入门】第五课 - 加粗和倾斜的字体们
这一小节,我们说一些常用的HTML文本格式化的标签知识。可能你会觉得HTML知识比较零散,有好多标签。没错,就是比较零散,标签比较多。正式这些形形色色的HTML标签们,组成了丰富多彩的网页元素。 但是在刚学习的时候&…...

解决树形表格 第一列中文字没有对齐
二级分类与一级分类的文字没有对齐 <el-table:data"templateStore.hangyeList"style"width: 100%"row-key"id":tree-props"{ children: subData, hasChildren: hasChildren }" ><el-table-column prop"industryCode&quo…...
三级_网络技术_09_IP地址规划技术
1.某企业产品部的IP地址块为211.168.15.192/26,市场部的为211.168.15.160/27,财务部的为211.168.15.128/27,这三个地址块经聚合后的地址为()。 211.168.15.0/25 211.168.15.0/26 211.168.15.128/25 211.168.15.128/26 2.若某大学分配给计…...
力扣1878.矩阵中最大的三个菱形和
力扣1878.矩阵中最大的三个菱形和 斜前缀和 遍历矩阵元素,同时求当前点左下右下两位置的前缀和枚举每个菱形中心,遍历边长 int sum1[101][101];int sum2[101][101];class Solution {public:vector<int> getBiggestThree(vector<vector<in…...
ELB和VPC是云计算领域中的两个术语,通常与Amazon Web Services (AWS)相关联
ELB 和 VPC 是云计算领域中的两个术语,通常与亚马逊云服务(AWS)相关: 1. **ELB (Elastic Load Balancer)**: - 这是AWS提供的一种服务,用于自动分配进入应用程序的流量,以实现高可用性和容错…...

家政维修平台实战20:权限设计
目录 1 获取工人信息2 搭建工人入口3 权限判断总结 目前我们已经搭建好了基础的用户体系,主要是分成几个表,用户表我们是记录用户的基础信息,包括手机、昵称、头像。而工人和员工各有各的表。那么就有一个问题,不同的角色…...

前端开发面试题总结-JavaScript篇(一)
文章目录 JavaScript高频问答一、作用域与闭包1.什么是闭包(Closure)?闭包有什么应用场景和潜在问题?2.解释 JavaScript 的作用域链(Scope Chain) 二、原型与继承3.原型链是什么?如何实现继承&a…...

华为云Flexus+DeepSeek征文|DeepSeek-V3/R1 商用服务开通全流程与本地部署搭建
华为云FlexusDeepSeek征文|DeepSeek-V3/R1 商用服务开通全流程与本地部署搭建 前言 如今大模型其性能出色,华为云 ModelArts Studio_MaaS大模型即服务平台华为云内置了大模型,能助力我们轻松驾驭 DeepSeek-V3/R1,本文中将分享如何…...

企业如何增强终端安全?
在数字化转型加速的今天,企业的业务运行越来越依赖于终端设备。从员工的笔记本电脑、智能手机,到工厂里的物联网设备、智能传感器,这些终端构成了企业与外部世界连接的 “神经末梢”。然而,随着远程办公的常态化和设备接入的爆炸式…...

Kafka入门-生产者
生产者 生产者发送流程: 延迟时间为0ms时,也就意味着每当有数据就会直接发送 异步发送API 异步发送和同步发送的不同在于:异步发送不需要等待结果,同步发送必须等待结果才能进行下一步发送。 普通异步发送 首先导入所需的k…...

【从零学习JVM|第三篇】类的生命周期(高频面试题)
前言: 在Java编程中,类的生命周期是指类从被加载到内存中开始,到被卸载出内存为止的整个过程。了解类的生命周期对于理解Java程序的运行机制以及性能优化非常重要。本文会深入探寻类的生命周期,让读者对此有深刻印象。 目录 …...
【Android】Android 开发 ADB 常用指令
查看当前连接的设备 adb devices 连接设备 adb connect 设备IP 断开已连接的设备 adb disconnect 设备IP 安装应用 adb install 安装包的路径 卸载应用 adb uninstall 应用包名 查看已安装的应用包名 adb shell pm list packages 查看已安装的第三方应用包名 adb shell pm list…...

FFmpeg:Windows系统小白安装及其使用
一、安装 1.访问官网 Download FFmpeg 2.点击版本目录 3.选择版本点击安装 注意这里选择的是【release buids】,注意左上角标题 例如我安装在目录 F:\FFmpeg 4.解压 5.添加环境变量 把你解压后的bin目录(即exe所在文件夹)加入系统变量…...
redis和redission的区别
Redis 和 Redisson 是两个密切相关但又本质不同的技术,它们扮演着完全不同的角色: Redis: 内存数据库/数据结构存储 本质: 它是一个开源的、高性能的、基于内存的 键值存储数据库。它也可以将数据持久化到磁盘。 核心功能: 提供丰…...

基于开源AI智能名片链动2 + 1模式S2B2C商城小程序的沉浸式体验营销研究
摘要:在消费市场竞争日益激烈的当下,传统体验营销方式存在诸多局限。本文聚焦开源AI智能名片链动2 1模式S2B2C商城小程序,探讨其在沉浸式体验营销中的应用。通过对比传统品鉴、工厂参观等初级体验方式,分析沉浸式体验的优势与价值…...