Spring-IoC-加强

news2024/9/27 17:24:11

目录

简略介绍

理解介绍

IoC的优点

Spring的IoC

IoC是如何实现的

IoC能做什么

IoC和DI

Spring IoC过程

为什么框架需要反射

Spring Bean的循环依赖问题

IoC简单实现


  • 简略介绍

  • 所谓的IoC(inversion of control),就是控制反转的意思
  • 何为控制反转?
  • 可以根据字面意思理解,就是对于某个东西A,原来的控制权在使用方B,B想用就能用,不想用就不用
  • 现在把控制权交还给了A,只有A给了才能用,这样就是控制反转了
  • 可能说的有点抽象,更具体一点呢
  • 拿代码来说话:
    • 下面是一个没有IoC的例子:

    • 当有了IoC之后:

  • 也就是说,没有Spring的话,我们要使用的对象,需要我们自己创建
  • 而有了Spring的IoC之后,对象由IoC容器创建并管理,我们只需要在想要使用的时候从容器中获取就行了
  • 值得说明的是,IoC只是一种思想和理念,可以有不同的实现方式
  • 理解介绍

  • IoC—Inversion of Control,即“控制反转”,不是什么技术,而是一种设计思想
  • 在Java开发中,IoC意味着将你设计好的对象交给容器控制,而不是传统的在你的对象内部直接控制
  • (1)IoC 就是控制反转,是指创建对象的控制权的转移
  • 以前创建对象的主动权和时机是由自己把控的,而现在这种权力转移到 Spring 容器中,并由容器根据配置文件去创建实例和管理各个实例之间的依赖关系
  • 对象与对象之间松散耦合,也利于功能的复用
  • DI 依赖注入,和控制反转是同一个概念的不同角度的描述,即 应用程序在运行时依赖 IoC 容器来动态注入对象需要的外部资源
  • (2)最直观的表达就是,IoC 让对象的创建不用去 new 了,可以由 Spring自动生产,使用 java 的反射机制,根据配置文件在运行时动态的去创建对象以及管理对象,并调用对象的方法的
  • (3)Spring的 IoC 有三种注入方式:构造器注入,setter 方法注入,根据注解注入
  • IoC让相互协作的组件保持松散的耦合,而 AOP 编程允许你把遍布于应用各层的功能分离出来形成可重用的功能组件
  • IoC的优点

  • 使用IoC,有最少三个好处:
    • 1-使用者不用关心引用bean的实现细节
      • 譬如对于 B b = new A(c,d,e,f); 来说,如果B要使用A,那还要把c,d,e,f多个类全都感知一遍,这显然是非常麻烦且不合理的
    • 2-不用创建多个相同的bean导致浪费
      • 仍然是:

      • 如果B和Z都引用了A,那么B和Z就可能new 两个A实例,实际上,我们只需要一个就好了
    • 3-Bean的修改使用方无需感知
      • 同样是上面的例子,假如说Bean A需要修改,如果没有IoC的话,所有引用到A的其他bean都需要感知这个逻辑,并且做对应的修改
      • 但是如果使用了IoC,其他bean就完全不用感知到
  • 列举一些 IoC 的一些好处:
    • 资源集中管理配置
    • 它将最小化应用程序中的代码量
    • 它以最小的影响和最少的侵入机制促进松耦合
    • 它支持即时的实例化和延迟加载 Bean 对象
    • 它将使您的应用程序易于测试,因为它不需要单元测试用例中的任何单例或 JNDI 查找机制
  • Spring的IoC

  • 对于Spring的IoC来说,它是IoC思想的一种实现方式
  • 在容器启动的时候,它会根据每个bean的要求,将bean注入到Spring Container中
  • 如果有其他bean需要使用,就直接从容器中获取即可,如下图所示:

  • Spring 框架的核心是 Spring IoC 容器
  • 容器创建 Bean 对象,将它们装配在一起,配置它们并管理它们的完整生命周期
    • Spring 容器使用依赖注入来管理组成应用程序的 Bean 对象
    • 容器通过读取提供的配置元数据 Bean Definition 来接收对象进行实例化,配置和组装的指令
    • 该配置元数据 Bean Definition 可以通过 XML,Java 注解或 Java Config 代码提供
  • IoC是如何实现的

  • 使用Spring的IoC容器能力,非常简单,如下代码所示:

  • 从上面的代码中,我们也能看出来Spring的IoC是如何实现的:
    • 1-从配置元数据中获取要DI的业务POJO(这里的配置元数据包括xml,注解,configuration类等)
    • 2-将业务POJO形成BeanDefinition注入到Spring Container中
    • 3-使用方通过ApplicationContext从Spring Container直接获取即可
    • 如下图所示:

  • IoC能做什么

  • 所谓IoC,对于Spring框架来说,就是将对象的创建和对象间的依赖关系交给IoC容器管理
  • 将对象的控制权由业务对象转移到IoC容器,所以叫控制反转
  • Spring所倡导的开发方式就是如此,所有的类都会在Spring容器中登记,告诉Spring你是个什么东西,你需要什么东西,然后Spring会在系统运行到适当的时候,把你要的东西主动给你,同时也把你交给其他需要你的东西
  • 所有的类的创建、销毁都由Spring来控制,也就是说控制对象生存周期的不再是引用它的对象,而是Spring
  • 对于某个具体的对象而言,以前是它控制其他对象,现在是所有对象都被Spring控制,所以这叫控制反转
  • IoC不是一种技术,只是一种思想,一个重要的面向对象编程的法则,它能指导我们如何设计出松耦合、更优良的程序
  • 传统应用程序都是由我们在类内部主动创建依赖对象,从而导致类与类之间高耦合,难于测试
  • 有了IoC容器后,把创建和查找依赖对象的控制权交给了容器,由容器进行注入组合对象,所以对象与对象之间是松散耦合,这样也方便测试,利于功能复用,更重要的是使得程序的整个体系结构变得非常灵活
  • 其实IoC对编程带来的最大改变不是从代码上,而是从思想上,发生了“主从换位”的变化
  • 应用程序原本是老大,要获取什么资源都是主动出击,但是在IoC/DI思想中,应用程序就变成被动的了,被动的等待IoC容器来创建并注入它所需要的资源
  • IoC和DI

  • DI—Dependency Injection,即“依赖注入”:组件之间依赖关系由容器在运行期决定,形象的说,即由容器动态的将某个依赖关系注入到组件之中
  • 理解DI的关键是:“谁依赖谁,为什么需要依赖,谁注入谁,注入了什么”
  • 来深入分析一下:
    • 谁依赖于谁:当然是应用程序依赖于IoC容器
    • 为什么需要依赖:应用程序需要IoC容器来提供对象需要的外部资源
    • 谁注入谁:很明显是IoC容器注入应用程序某个对象,应用程序依赖的对象
    • 注入了什么:就是注入某个对象所需要的外部资源(包括对象、资源、常量数据)
  • IoC和DI有什么关系呢?
  • 其实它们是同一个概念的不同角度描述,由于控制反转概念比较含糊(可能只是理解为容器控制对象这一个层面,很难让人想到谁来维护对象关系)
  • 所以2004年大师级人物Martin Fowler又给出了一个新的名字:“依赖注入”,相对IoC而言,“依赖注入”明确描述了“被注入对象依赖IoC容器配置依赖对象”
  • Spring IoC过程

  • Spring 的 IoC 设计支持以下功能:
    • 依赖注入
    • 依赖检查
    • 自动装配
    • 支持集合
    • 指定初始化方法和销毁方法
    • 支持回调某些方法(但是需要实现 Spring 接口,略有侵入)
  • 对于 IoC 来说,最重要的就是容器
  • 容器管理着 Bean 的生命周期,控制着 Bean 的依赖注入
  • 那么, Spring 如何设计容器的呢?
  • Spring 作者 Rod Johnson 设计了两个接口用以表示容器
    • BeanFactory
    • ApplicationContext
  • BeanFactory 粗暴简单,可以理解为就是个 HashMap,Key 是 BeanName,Value 是 Bean 实例
  • 通常只提供注册(put),获取(get)这两个功能,可以称之为“低级容器”
  • ApplicationContext 可以称之为“高级容器”
  • 因为他比 BeanFactory 多了更多的功能
  • 他继承了多个接口,因此具备了更多的功能
  • 例如资源的获取,支持多种消息(例如 JSP tag 的支持),对 BeanFactory 多了工具级别的支持等待
  • 所以你看他的名字,已经不是 BeanFactory 之类的工厂了,而是“应用上下文”,代表着整个大容器的所有功能
  • 该接口定义了一个 refresh 方法,此方法是所有阅读 Spring 源码的人的最熟悉的方法,用于刷新整个容器,即重新加载/刷新所有的bean
  • 当然,除了这两个大接口,还有其他的辅助接口,但我今天不会花太多篇幅介绍他们
  • 为了更直观的展示 “低级容器” 和 “高级容器” 的关系,我这里通过常用的 ClassPathXmlApplicationContext类,来展示整个容器的层级 UML 关系

  • 最上面的 BeanFactory,下面的 3 个绿色的,都是功能扩展接口,这里就不展开讲
  • 看下面的隶属 ApplicationContext 粉红色的 “高级容器”,依赖着 “低级容器”,这里说的是依赖,不是继承
  • 他依赖着 “低级容器” 的 getBean 功能
  • 而高级容器有更多的功能:支持不同的信息源头,可以访问文件资源,支持应用事件(Observer 模式)
  • 通常用户看到的就是“高级容器”
  • 但 BeanFactory 也非常够用;左边灰色区域的是 “低级容器”,只负载加载 Bean,获取 Bean
  • 容器其他的高级功能是没有的
  • 例如上图画的 refresh 刷新 Bean 工厂所有配置,生命周期事件回调等
  • 解释了低级容器和高级容器,我们可以看看一个 IoC 启动过程是什么样子的
  • 说白了,就是 ClassPathXmlApplicationContext 这个类,在启动时,都做了啥
    • 1-用户构造 ClassPathXmlApplicationContext(简称 CPAC)
    • 2-CPAC 首先访问了 “抽象高级容器” 的 final 的 refresh 方法,这个方法是模板方法
    • 所以要回调子类(低级容器)的 refreshBeanFactory 方法,这个方法的作用是使用低级容器加载所有 BeanDefinition 和 Properties 到容器中
    • 3-低级容器加载成功后,高级容器开始处理一些回调,例如 Bean 后置处理器
    • 回调 setBeanFactory 方法;或者注册监听器等,发布事件,实例化单例 Bean 等等功能
    • 这些功能,随着 Spring 的不断升级,功能越来越多,很多人在这里迷失了方向
  • 简单说就是:
    • 1-低级容器 加载配置文件(从 XML,数据库,Applet),并解析成 BeanDefinition 到低级容器中
    • 2-加载成功后,高级容器启动高级功能,例如接口回调,监听器,自动实例化单例,发布事件等等功能
  • 好,当我们创建好容器,就会使用 getBean 方法,获取 Bean,而 getBean 的流程如下:

  • 从图中可以看出,getBean 的操作都是在低级容器里操作的
  • 其中有个递归操作,这个是什么意思呢?
  • 假设:当 Bean_A 依赖着 Bean_B,而这个 Bean_A 在加载的时候,其配置的 ref = “Bean_B” 在解析的时候只是一个占位符,被放入了 Bean_A 的属性集合中,当调用 getBean 时,需要真正 Bean_B 注入到 Bean_A 内部时,就需要从容器中获取这个 Bean_B,因此产生了递归
  • 为什么不是在加载的时候,就直接注入呢?
  • 因为加载的顺序不同,很可能 Bean_A 依赖的 Bean_B 还没有加载好,也就无法从容器中获取,你不能要求用户把 Bean 的加载顺序排列好,这是不人道的
  • 所以,Spring 将其分为了 2 个步骤:
    • 1-加载所有的 Bean 配置成 BeanDefinition 到容器中,如果 Bean 有依赖关系,则使用占位符暂时代替
    • 2-然后,在调用 getBean 的时候,进行真正的依赖注入,即如果碰到了属性是 ref 的(占位符),那么就从容器里获取这个 Bean,然后注入到实例中 —— 称之为依赖注入
  • 可以看到,依赖注入实际上,只需要 “低级容器” 就可以实现
  • 这就是 IoC
  • 所以 ApplicationContext refresh 方法里面的操作不只是 IoC,是高级容器的所有功能(包括 IoC),IoC 的功能在低级容器里就可以实现
  • 小结:
  • IoC 在 Spring 里,只需要低级容器就可以实现,2 个步骤:
    • 加载配置文件,解析成 BeanDefinition 放在 Map 里,如果 Bean 有依赖关系,则使用占位符暂时代替
    • 调用 getBean 的时候,从 BeanDefinition 所属的 Map 里,拿出 Class 对象进行实例化,同时,如果有依赖关系,将递归调用 getBean 方法 —— 完成依赖注入
  • 上面就是 Spring 低级容器(BeanFactory)的 IoC
  • 至于高级容器 ApplicationContext,他包含了低级容器的功能,当他执行 refresh 模板方法的时候,将刷新整个容器的 Bean
  • 同时其作为高级容器,包含了太多的功能
  • 一句话,他不仅仅是 IoC
  • 他支持不同信息源头,支持 BeanFactory 工具类,支持层级容器,支持访问文件资源,支持事件发布通知,支持接口回调等等
  • 可以预见,随着 Spring 的不断发展,高级容器的功能会越来越多
  • 为什么框架需要反射

  • IoC容器的作用需求就是在框架运行后通过读取类定义的配置文件去帮我们创建任意对象,执行任意方法
  • 因为框架先于客户编写程序运行,无法事先得到程序类,只能通过反射
  • Spring Bean的循环依赖问题

  • 循环依赖其实就是循环引用,也就是两个或者两个以上的bean互相持有对方,最终形成闭环
  • 比如A依赖于B,B依赖于C,C又依赖于A
  • 如下图:

  • 注意,这里不是函数的循环调用,是对象的相互依赖关系
  • 循环调用其实就是一个死循环,除非有终结条件
  • Spring中循环依赖场景有:
  • (1)构造器的循环依赖
  • (2)field属性的循环依赖
  • 第一种:构造器参数循环依赖
  • Spring容器会将每一个正在创建的 Bean 标识符放在一个“当前创建Bean池”中,Bean标识符在创建过程中将一直保持在这个池中,因此如果在创建Bean过程中发现自己已经在“当前创建Bean池”里时将抛出BeanCurrentlyInCreationException异常表示循环依赖
  • 而对于创建完毕的Bean将从“当前创建Bean池”中清除掉
  • 如果大家理解开头那句话的话,这个报错应该不惊讶
  • Spring容器先创建单例StudentA,StudentA依赖StudentB,然后将A放在“当前创建Bean池”中,此时创建StudentB,StudentB依赖StudentC,然后将B放在“当前创建Bean池”中,此时创建StudentC,StudentC又依赖StudentA,但是,此时StudentA已经在池中,所以会报错,因为在池中的Bean都是未初始化完的,所以会依赖错误(初始化完的Bean会从池中移除)
  • 第二种:setter方式单例,默认方式(三级缓存可以解决)
  • 当然,Spring对于循环依赖的解决不是无条件的,首先前提条件是针对scope单例并且没有显式指明不需要解决循环依赖的对象
  • 而且要求该对象没有被代理过

  • 如图中前两步骤得知:Spring是先将Bean对象实例化之后再设置对象属性的
  • 为什么用set方式就不报错了呢
  • “三级缓存”主要是指

  • 让我们来分析一下“A的某个field或者setter依赖了B的实例对象,同时B的某个field或者setter依赖了A的实例对象”这种循环依赖的情况
  • A首先完成了初始化的第一步,并且将自己提前曝光到singletonFactories(三级缓存)中
  • 此时进行初始化的第二步,发现自己依赖对象B,此时就尝试去get(B),发现B还没有被create,所以走create流程,B在初始化第一步的时候发现自己依赖了对象A,于是尝试get(A),尝试一级缓存singletonObjects(肯定没有,因为A还没初始化完全),尝试二级缓存earlySingletonObjects(也没有),尝试三级缓存singletonFactories,由于A通过ObjectFactory将自己提前曝光了,所以B能够通过ObjectFactory.getObject拿到A对象(虽然A还没有初始化完全,但是总比没有好呀)
  • B拿到A对象后顺利完成了初始化阶段1、2、3,完全初始化之后将自己放入到一级缓存singletonObjects中
  • 此时返回A中,A此时能拿到B的对象顺利完成自己的初始化阶段2、3,最终A也完成了初始化,长大成人,进去了一级缓存singletonObjects中,而且更加幸运的是,由于B拿到了A的对象引用,所以B现在hold住的A对象也蜕变完美了!一切都是这么神奇
  • Spring通过三级缓存加上“提前曝光”机制,配合Java的对象引用原理,比较完美地解决了某些情况下的循环依赖问题
  • 第三种:setter方式原型,prototype
  • 为什么原型模式就报错了呢?
  • 对于“prototype”作用域Bean,Spring容器无法完成依赖注入,因为“prototype”作用域的Bean,Spring容器不进行缓存,因此无法提前暴露一个创建中的Bean
  • IoC简单实现

  • 先从简单的 IOC 容器实现开始,最简单的 IOC 容器只需4步即可实现,如下:
    • 1-加载 xml 配置文件,遍历其中的标签
    • 2-获取标签中的 id 和 class 属性,加载 class 属性对应的类,并创建 bean
    • 3-遍历标签中的标签,获取属性值,并将属性值填充到 bean 中
    • 4-将 bean 注册到 bean 容器中

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

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

相关文章

Django基础三——视图函数

文章目录 一、基本了解1.1 Django内置函数1.2 http请求流程 二、HttpRequest对象(接受客户端请求)2.1 常用属性2.2 常用方法2.3 服务端接收URL参数2.4 QueryDict对象2.5 案例2.5.1 表单GET提交2.5.2 表单POST提交2.5.3 上传文件 三、HttpResponse对象&am…

气传导耳机品牌推荐?四大品牌气传导耳机推荐

​越来越多小伙伴开始使用气传导耳机了,面对市面上参差不齐的气传导耳机,导致很多小伙伴找不到适合自己的那款耳机了,面对这些问题,我整理了几款好用的气传导耳机给大家挑选和参考,希望都能找到心仪那款。 ①NANK南卡…

Docker-compose 容器编排

1. 是什么 Compose 是 Docker 公司推出的一个工具软件,可以管理多个 Docker 容器组成一个应用。你需要定义一个 YAML 格式的配置文件docker-compose.yml,写好多个容器之间的调用关系。然后,只要一个命令,就能同时启动/关闭这些容器…

vscode+ros开发环境搭建

目录 介绍 前提 vscode安装 vscode插件安装 工作空间准备 打开vscode 创建catkin包 编写cpp代码 编译 运行 启动ros服务 监听话题 启动ros测试 介绍 ros开发是机器人开发中必不可少的工作,语言选择可以是c,也可以是python。工具的话,不能像wi…

Mysql 基本概念

数据库的组成 数据 数据是描述事务的符号记录;包括数字、文字、图形、图像、声音、档案记录等 以“记录“形式按统一的格式进行存储 表 将不同的记录以行和列的方式组合成了表 用来存储具体数据 数据库 它就是所有不同属性表的集合 以一定的组织方式存储的…

vue 简单实验 v-for 循环

1.代码 <script src"https://unpkg.com/vuenext" rel"external nofollow" ></script> <div id"list-rendering"><ol><li v-for"todo in todos">{{ todo.text }}</li></ol> </div> &…

数据API服务管理功能:解放数据潜力,提升业务效率

数据API服务的重要性 在数字化时代&#xff0c;数据被认为是企业的重要资产。数据API服务的管理功能能够有效帮助企业实现数据的整合和利用。通过合理的数据API服务管理&#xff0c;企业可以更好地解放数据潜力&#xff0c;提升业务效率。 ​ 解放数据潜力 数据API服务管理功…

解决git上传远程仓库时的大文件提交

在git中超过100M的文件会上传失败&#xff0c;而当一个文件超过50M时会给你警告&#xff0c;如下 warning: File XXXXXX is 51.42 MB; this is larger than GitHubs recommended maximum file size of 50.00 MB 解决这种问题&#xff0c;首先在项目的.git文件夹中找到.gitigno…

git push时,由于commit了大文件无法成功push的解决办法

2句命令解决&#xff01; 如图可以看见大文件的md5值&#xff0c;复制下来&#xff0c;以下命令会使用到 命令1&#xff1a; git rev-list --objects --all | grep b8d13387c0dfd7a8cec9ff0f6c8ded06eb21556f执行上面命令将得到&#xff0c;如下的输出&#xff0c;可以得知是…

C++基础Ⅱ变量

目录儿 4 变量4.1 原始数据类型字符 char整型 short整型 int整型 long整型 long long单精度浮点型 float双精度浮点型 double布尔型 bool 4.2 sizeof 关键字 5 指针和引用 4 变量 4.1 原始数据类型 原始数据类型是构建C程序的最基础数据类型 所有数据都是基于这些原始数据类型…

度加剪辑App的MMKV应用优化实践

作者 | 我爱吃海米 导读 移动端开发中&#xff0c;IO密集问题在很多时候没有得到充足的重视和解决&#xff0c;贸然的把IO导致的卡顿放到异步线程&#xff0c;可能会导致真正的问题被掩盖&#xff0c;前人挖坑后人踩。其实首先要想的是&#xff0c;数据存储方式是否合理&#x…

HQL解决连续三天登陆问题

1.背景 统计连续登录天数超过3天的用户&#xff0c;输出信息包括&#xff1a;用户id&#xff0c;登录天数&#xff0c;起始时间&#xff0c;结束时间&#xff1b; 2.准备数据 -- 建表 create table if not exists user_login_3days(user_id STRING,login_date date );--插入…

查询数据库字段信息 mysql

属性&#xff1a; SELECT TABLE_SCHEMA AS 库名, TABLE_NAME AS 表名, COLUMN_NAME AS 字段名, ORDINAL_POSITION AS 字段顺序, COLUMN_DEFAULT AS 默认值, IS_NULLABLE AS 是否为空, DATA_TYPE …

怎么把pdf文件变小?值得一看的文件压缩方法

现在很多平台对于上传的文件大小是有限制的&#xff0c;如果压缩成压缩包的形式发送&#xff0c;虽然可以减小一点体积&#xff0c;但对方无法直接打开预览文件内的内容&#xff0c;很不方便&#xff0c;怎么才能直接将PDF文件的体积压缩变小呢&#xff1f;下面就给大家汇总了几…

GB2312转UTF-8部分中文乱码

现象 最近写了个txt导入&#xff0c;客户反馈有时候导入的数据&#xff0c;会出现个别中文乱码的现象&#xff0c;但是我之前已经做过编码转换处理了&#xff0c;统一转成了UTF-8。 比如“鞠婧祎”,导入进来是这样&#xff1a; 排查思路 首先看了一下这个文本的编码格式&am…

Window Server 与 Windows 系统开关机日志查看方法

目录 Windows/Windows Server 查看日志Windows 系统常用的事件 ID 环境&#xff1a;Windows Server 2019 &#xff08;也适用于 Windows 其他系统&#xff09;。 不同版本的 Windows 图标可能有所不同&#xff0c;但是服务器级 Windows Server 与普通桌面级 Windows 还会有些操…

低代码平台是为何而生?低代码平台发展前景又如何呢?

低代码平台是为何而生&#xff1f;低代码平台发展前景又如何呢&#xff1f;低代码平台在近年来已经吸引了越来越多的关注&#xff0c;被认为是一种能够加速应用程序开发的解决方案。低代码平台虽然还存在着各种各样的问题&#xff0c;但是低代码平台的前景依然十分广阔。 下面…

放苹果(巧用递归)--夏令营

题目 tips&#xff1a; 1.写递归要有递归边界条件&#xff0c;递归过程就是向边界不断靠近 这里注意&#xff1a;虽然题目给的m,n输入数据范围是>1的&#xff0c;但不代表边界就是这个&#xff1b; 首先&#xff0c;n0肯定是不存在的&#xff0c;所以n的边界肯定是1&#…

粒子目标_雨滴

nParticleShape1.goalU parentU; nParticleShape1.goalV parentV; 使用纹理发射nParticle nParticleShape1.goalV .01; nParticleShape1.goalV .01*-1; goalV if(nParticleShape1.goalV <.045) { nParticleShape1.lifespanPP -1; } 粒子轨迹 nParticleShape1.goalU …

【腾讯云 TDSQL-C Serverless 产品测评】“橡皮筋“一样的数据库『MySQL高压篇』

【腾讯云 TDSQL-C Serverless 产品测评】"橡皮筋"一样的数据库 活动介绍服务一览何为TDSQL &#xff1f;Serverless 似曾相识&#xff1f; 降本增效&#xff0c;不再口号&#xff1f;动手环节 --- "压力"山大实验前瞻稍作简介资源扩缩范围&#xff08;CCU&…