【Gradle】(三)详细聊聊依赖管理:坐标、依赖配置、依赖传递、依赖冲突

news2024/11/15 21:29:51

文章目录

  • 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,改动量很小时,可以使用增量版本号。
  • 里程碑版本:就是项目的当前版本处于一个什么样的阶段了,常见的里程碑版本有 SNAPSHOTalphabetareleaseGA 等。
    在里程碑的版本中,标注SNAPSHOT的为开发版,此时会存在大量的代码变动,alphabeta分别对应的是内测版与公测版这三个版本都是属于不稳定版本,使用的时候非常容易踩坑,所以一般只用的demo体验,在正式环境中不能使用。
    releaseGA都属于是稳定的正式版本,可以在正式环境中使用。

下面是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 ClasspathRuntime 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 false
    id '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_8

    java {
        withSourcesJar()
    }

    publishing {
        publications {
            demo(MavenPublication) {
                from components.java
            }
        }

        repositories {
            maven {
                name = "mavenNexus"
                allowInsecureProtocol = true
                def 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 : releasesRepoUrl
                credentials {
                    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-demob-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-demolombok,其中 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等,也可能是其他不规则的符号,或者没有限定符。

下面的官网提供的例子,如何分解基础版本号与限定符:
在这里插入图片描述
在版本号里面有.,+,-,_这样的分隔符,以及字母和数字之间有一个空串分隔符,出现这些分隔符的时候会找第一个不是.的分隔符,左侧就是基础版本号,右侧就是限定符。

版本号排序规则
  • 第一步:通过分隔符将版本号拆分成不同的组成部分
    通过.,+,-,_这几个符号进行拆分,同时,如果有字母和数字的组合,也会拆解成不同的部分。
    例如:1a11.a.11-a-1 不管分隔符是什么,都会拆分成[1,a,1]三个部分。
  • 第二步:分别对比每个部分的值
    就像字符串的对比那样,从左到右,一个一个的对比,其大小规则为:2 > 1 > 0 > b > a > B > Am遇到多个部分组合比较的时候,还要注意一个规则: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种组合,分别对应不同的功能:

  • 排除所有传递依赖
    artifactIdexclue的参数中使用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 的依赖管理展开了全方位且极为详尽的介绍。在此过程中,清晰明确地提及了诸如坐标、依赖的基础概念、依赖配置、依赖传递还有依赖冲突等相关特性。在充分熟知并掌握了这些特性之后,于后续开展的工作当中,就能够更加精确、细致地对依赖进行管理,并且可以妥善、有效地处理由依赖冲突所引发的各种各样的问题。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1910133.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

mybatilsplaus 常用注解

官网地址 baomidou注解配置

数据高效交互丨DolphinDB Redis 插件使用指南

DolphinDB 是一个高性能的分布式数据库。通过 Redis 插件&#xff0c;DolphinDB 用户可以轻松地与 Redis 数据库进行交互。用户不仅可以从 DolphinDB 向 Redis 发送数据&#xff0c;实现高速的数据写入操作&#xff1b;还可以从 Redis 读取数据&#xff0c;将实时数据流集成到 …

关于嵌入式系统中的LED控制程序的一篇爽文

嵌入式系统中的LED控制程序 在嵌入式系统中控制LED是一个很常见的任务&#xff0c;可以用于指示状态、显示信息等。我们将使用C语言编写一个简单的LED控制程序&#xff0c;该程序将控制一个虚拟的LED&#xff0c;但可以根据需要将其扩展到实际的硬件上。 准备工作 在开始之前…

灯塔音乐网,灯塔音乐下载官网

音乐&#xff0c;这个无形的艺术&#xff0c;自古以来就伴随着人类的生活&#xff0c;成为了我们表达情感、沟通思想、寻求共鸣的重要桥梁。在我们的日常生活中&#xff0c;音乐无处不在&#xff0c;它不仅仅是一种娱乐方式&#xff0c;更是一种生活态度&#xff0c;一种精神寄…

从零开始做题:emoji

题目 给出一张图片 解题 from PIL import Image import random # 读取txt文件 with open("rgb.txt", "r") as file: lines file.readlines() # 跳过第一行&#xff08;包含尺寸信息&#xff09; lines lines[1:] # 提取RGB颜色值 colors…

职升网:初中毕业如通过什么方式考中专学历?

对于许多初中毕业生而言&#xff0c;想要进一步提升自己的学历&#xff0c;中专是一个不错的选择。考取中专学历需要遵循一定的步骤&#xff0c;以下是具体的指导&#xff1a; 了解中专入学要求&#xff1a; 首先&#xff0c;你需要详细了解不同中专学校的入学要求。这通常包…

ubuntu下aarch64-linux-gnu(交叉编译) gdb/gdbserver

ubuntu下aarch64-linux-gnu(交叉编译) gdb/gdbserver gdb是一款开源的、强大的、跨平台的程序调试工具。主要用于在程序运行时对程序进行控制和检查&#xff0c;如设置断点、单步执行、查看变量值、修改内存数据等&#xff0c;从而帮助开发者定位和修复代码中的错误。 gdbserve…

熬了一晚上,我从零实现了 Transformer 模型,把代码讲给你听

自从彻底搞懂Self_Attention机制之后&#xff0c;笔者对Transformer模型的理解直接从地下一层上升到大气层&#xff0c;瞬间打通任督二脉。夜夜入睡之前&#xff0c;那句柔情百转的"Attention is all you need"时常在耳畔环绕&#xff0c;情到深处不禁拍床叫好。于是…

无线领夹麦克风怎么挑选,降噪麦克风能消除旁边人说话声吗?

在自媒体行业的蓬勃发展下&#xff0c;音频设备的地位愈发显著&#xff0c;尤其是麦克风这一关键组件。它见证了从传统新闻采访、电视节目制作到现代网络直播、个人视频日志&#xff08;Vlog&#xff09;的演变。随着技术的进步和应用场景的多样化&#xff0c;麦克风的种类也日…

软考分数线有3种,低于45分也能拿证!

软考合格分数标准是45分&#xff0c;这个是广泛为人所知的。然而&#xff0c;有些地区即使没有达到45分也可以获得证书&#xff0c;这一点许多考生并不清楚。总的来说&#xff0c;软考的合格标准有三种&#xff01; ● 全国分数线&#xff1a;通常是各科45分及格&#xff0c;证…

将WordPress的文章重新排序的3个方法

有效的调整文章显示顺序看开可以更好突出内容&#xff0c;还可以保持网站的新鲜感&#xff0c;今天我将带您了解三种方法&#xff0c;通过重新排序文章显著提升网站的吸引力。我们将逐步讲解从调整设置到使用插件以及“置顶”文章的每一种方法&#xff0c;确保WordPress 新手也…

学生护眼台灯十大排名有哪些?品牌台灯质量前十的排名曝光!

在孩子学习过程中&#xff0c;有一样物品的重要性不容忽视&#xff0c;那就是一盏提供舒适光源的台灯。面对不断增加的学业负担&#xff0c;孩子们经常需要在夜晚借助台灯的光亮进行学习&#xff0c;这已经成为了家庭生活中普遍的情景。然而&#xff0c;我们必须给予足够的关注…

股票分析系统设计方案大纲与细节

股票分析系统设计方案大纲与细节 一、引言 随着互联网和金融行业的迅猛发展,股票市场已成为重要的投资渠道。投资者在追求财富增值的过程中,对股票市场的分析和预测需求日益增加。因此,设计并实现一套高效、精准的股票分析系统显得尤为重要。本设计方案旨在提出一个基于大…

智启未来,共筑工业软件新梦 ——清华大学博士生天洑软件实习启航

2024年6月30日&#xff0c;清华大学工程物理系、深圳国际研究生院、航天航空学院、机械工程系、能源与动力工程系的10名博士研究生抵达南京天洑软件有限公司&#xff0c;正式开启为期6周的博士生必修环节社会实践。 “天洑软件清华基地”成立于2021年&#xff0c;旨在为清华理工…

智能锁赛博化,凯迪仕携全球顶尖科技亮相建博会!

7月8日&#xff0c;作为大家居建材行业全球规模第一大展&#xff0c;2024中国建博会&#xff08;广州&#xff09;在广交会展馆正式拉开序幕。据官方数据显示&#xff0c;本届展会展出规模展览总规模近40万平方米&#xff0c;建筑装饰领域各细分题材的一线品牌几乎全部参展。 其…

[图解]企业应用架构模式2024新译本讲解24-标识映射3

1 00:00:00,460 --> 00:00:02,580 超类定义了一个抽象方法 2 00:00:03,170 --> 00:00:03,450 3 00:00:06,410 --> 00:00:09,690 把reader内容 4 00:00:10,870 --> 00:00:12,350 把它变成一个领域对象 5 00:00:13,690 --> 00:00:15,800 但这里只是把它变成一个…

SpringBoot + MyBatisPlus 实现多租户分库

一、引言 在如今的软件开发中&#xff0c;多租户(Multi-Tenancy)应用已经变得越来越常见。多租户是一种软件架构技术&#xff0c;它允许一个应用程序实例为多个租户提供服务。每个租户都有自己的数据和配置&#xff0c;但应用程序实例是共享的。而在我们的Spring Boot MyBati…

【吊打面试官系列-MyBatis面试题】什么是 MyBatis 的接口绑定?有哪些实现方式?

大家好&#xff0c;我是锋哥。今天分享关于 【什么是 MyBatis 的接口绑定&#xff1f;有哪些实现方式&#xff1f;】面试题&#xff0c;希望对大家有帮助&#xff1b; 什么是 MyBatis 的接口绑定&#xff1f;有哪些实现方式&#xff1f; 接口绑定&#xff0c;就是在 MyBatis 中…

【windows OBS开启直播】Windows搭建RTMP视频流服务(Nginx服务器版)

如果您想在windows 电脑上设置RTMP服务器&#xff0c;并使用VLC播放器播放OBS的直播流&#xff0c;您可以使用一个本地的RTMP服务器软件&#xff0c;如nginx配合nginx-rtmp-module来搭建。下面 详细介绍下如何搭建此视频流服务。 1、安装和配置本地RTMP服务器 步骤1&#xff…

在Morelogin中使用IPXProxy海外代理IP的设置指南

Morelogin指纹浏览器是市场上较受欢迎的指纹浏览器&#xff0c;允许用户管理多个账号并进行自动化操作。它提供免费环境供用户进行体验&#xff0c;并且操作起来非常简单。大多数人都会将Morelogin指纹浏览器和海外代理IP进行使用&#xff0c;来应用于多种场景&#xff0c;如电…