【Spring篇】IOC相关内容
🍓系列专栏:Spring系列专栏
🍉个人主页:个人主页
目录
一、bean基础配置
1.bean基础配置(id与class)
2.bean的name属性
3.bean作用范围scope配置
二、bean实例化
1.构造方法实例化
2.分析Spring的错误信息
3.静态工厂实例化
4.实例工厂
5.FactoryBean
三、bean的生命周期
1.环境准备
2.生命周期设置
3.close关闭容器
一、bean基础配置
1.bean基础配置(id与class)
<bean id="" class=""/>

这其中需要大家重点掌握的是:bean标签的id和class属性的使用。
class属性能不能写接口如BookDao的类全名呢?
- 答案肯定是不行,因为接口是没办法创建对象的。
2.bean的name属性
首先来看下别名的配置说
步骤1:配置别名
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"><!--name:为bean指定别名,别名可以有多个,使用逗号,分号,空格进行分隔--><bean id="bookService" name="service service4 bookEbi" class="com.itheima.service.impl.BookServiceImpl"><property name="bookDao" ref="bookDao"/></bean><!--scope:为bean设置作用范围,可选值为单例singloton,非单例prototype--><bean id="bookDao" name="dao" class="com.itheima.dao.impl.BookDaoImpl" scope="prototype"/>
</beans>
public class AppForName {public static void main(String[] args) {ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");BookService bookService = (BookService) ctx.getBean("service4");bookService.save();}
}
运行:
注意事项:
如果不存在,则会报错,如下:
获取bean无论是通过id还是name获取,如果无法获取到,将抛出异常 NoSuchBeanDefinitionException
3.bean作用范围scope配置
关于bean的作用范围是bean属性配置的一个重点内容。
看到这个作用范围,我们就得思考bean的作用范围是来控制bean哪块内容的? 我们先来看下bean作用范围的配置属性:
验证IOC容器中对象是否为单例

结论:默认情况下,Spring创建的bean对象都是单例的
配置bean为非单例
在Spring配置文件中,配置scope属性来实现bean的非单例创建
- 在Spring的配置文件中,修改<bean>的scope属性
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"><!--name:为bean指定别名,别名可以有多个,使用逗号,分号,空格进行分隔--><bean id="bookService" name="service service2 bookEbi" class="com.itheima.service.impl.BookServiceImpl"><property name="bookDao" ref="bookDao"/></bean><!--scope:为bean设置作用范围,可选值为单例singloton,非单例prototype--><bean id="bookDao" name="dao" class="com.itheima.dao.impl.BookDaoImpl" scope="singleton"/>
</beans>
运行AppForScope,打印看结果:
将scope设置为prototype :
- singleton默认为单例
- prototype为非单例
- bean为单例的意思是在Spring的IOC容器中只会有该类的一个对象
- bean对象只有一个就避免了对象的频繁创建与销毁,达到了bean对象的复用,性能高
- 如果对象是有状态对象,即该对象有成员变量可以用来存储数据的,
- 因为所有请求线程共用一个bean对象,所以会存在线程安全问题。
- 如果对象是无状态对象,即该对象没有成员变量没有进行数据存储的,
- 因方法中的局部变量在方法调用完成后会被销毁,所以不会存在线程安全问题。
- 表现层对象
- 业务层对象
- 数据层对象
- 工具对象
哪些bean对象不适合交给容器进行管理?
- 封装实例的域对象,因为会引发线程安全问题,所以不适合。
二、bean实例化
- bean是如何创建的
- 实例化bean的三种方式,构造方法,静态工厂和实例工厂
1.构造方法实例化
public interface BookDao {public void save();
}
public class BookDaoImpl implements BookDao {public void save() {System.out.println("book dao save ...");}}
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="bookDao" class="com.itheima.dao.impl.BookDaoImpl"/>
</beans>
public class AppForInstanceBook {public static void main(String[] args) {ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");BookDao bookDao = (BookDao) ctx.getBean("bookDao");bookDao.save();}
}
public class BookDaoImpl implements BookDao {public BookDaoImpl() {System.out.println("book dao constructor is running ....");}public void save() {System.out.println("book dao save ...");}}


public class BookDaoImpl implements BookDao {private BookDaoImpl(int i) {System.out.println("book dao constructor is running ....");}public void save() {System.out.println("book dao save ...");}}

2.分析Spring的错误信息
接下来,我们主要研究下Spring的报错信息来学一学如阅读。
错误信息从下往上依次查看,因为上面的错误大都是对下面错误的一个包装,最核心错误是在最下面
- Caused by 翻译为引起,即出现错误的原因
- java.lang.NoSuchMethodException:抛出的异常为 没有这样的方法异常
- com.itheima.dao.impl.BookDaoImpl. <init> ():哪个类的哪个方法没有被找到导致的异常,<init> ()指定是类的构造方法,即该类的无参构造方法
如果最后一行错误获取不到错误信息,接下来查看第二层:
Exception in thread "main" org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'bookDao' defined in class path resource [applicationContext.xml]: Instantiation of bean failed; nested exception is org.springframework.beans.BeanInstantiationException: Failed to instantiate [com.itheima.dao.impl.BookDaoImpl]: No default constructor found; nested exception is java.lang.NoSuchMethodException: com.itheima.dao.impl.BookDaoImpl.<init>()
- nested:嵌套的意思,后面的异常内容和最底层的异常是一致的
- BeanInstantiationException:翻译为bean实例化异常
- No default constructor found:没有一个默认的构造函数被发现
3.静态工厂实例化
接下来研究Spring中的第二种bean的创建方式静态工厂实例化:
工厂方式创建bean
public class OrderDaoImpl implements OrderDao {public void save() {System.out.println("order dao save ...");}
}
public interface OrderDao {public void save();
}
//静态工厂创建对象
public class OrderDaoFactory {public static OrderDao getOrderDao(){System.out.println("factory setup....");return new OrderDaoImpl();}
}
public class AppForInstanceOrder {public static void main(String[] args) {//通过静态工厂创建对象OrderDao orderDao = OrderDaoFactory.getOrderDao();orderDao.save();}
}
如果代码中对象是通过上面的这种方式来创建的,如何将其交给Spring来管理呢?
静态工厂实例化
<bean id="orderDao" class="com.itheima.factory.OrderDaoFactory" factory-method="getOrderDao"/>

(2)在AppForInstanceOrder运行类,使用从IOC容器中获取bean的方法进行运行测试
public class AppForInstanceOrder {public static void main(String[] args) {//通过静态工厂创建对象
// OrderDao orderDao = OrderDaoFactory.getOrderDao();
// orderDao.save();ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");OrderDao orderDao = (OrderDao) ctx.getBean("orderDao");orderDao.save();}
}
4.实例工厂
接下来继续来研究Spring的第三种bean的创建方式实例工厂实例化:
环境准备
public interface UserDao {public void save();
}
public class UserDaoImpl implements UserDao {public void save() {System.out.println("user dao save ...");}
}
//实例工厂创建对象
public class UserDaoFactory {public UserDao getUserDao(){return new UserDaoImpl();}
}
public class AppForInstanceUser {public static void main(String[] args) {//创建实例工厂对象UserDaoFactory userDaoFactory = new UserDaoFactory();//通过实例工厂对象创建对象UserDao userDao = userDaoFactory.getUserDao();userDao.save();}
}

对于上面这种实例工厂的方式如何交给Spring管理呢?
实例工厂实例化
<bean id="userFactory" class="com.itheima.factory.UserDaoFactory"/>
<bean id="userDao" factory-method="getUserDao" factory-bean="userFactory"/>
- 创建实例化工厂对象,对应的是第一行配置
- 调用对象中的方法来创建bean,对应的是第二行配置
- factory-bean: 工厂的实例对象
- factory-method:工厂对象中的具体创建对象的方法名 , 对应关系如下 :

factory-mehod:具体工厂类中创建对象的方法名
(2)在AppForInstanceUser运行类,使用从IOC容器中获取bean的方法进行运行测试
public class AppForInstanceUser {public static void main(String[] args) {ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");UserDao userDao = (UserDao) ctx.getBean("userDao");userDao.save();}
}
实例工厂实例化的方式就已经介绍完了,配置的过程还是比较复杂,所以Spring为了简化这种配置方式就提供了一种叫FactoryBean的方式来简化开发。
5.FactoryBean
//FactoryBean创建对象
public class UserDaoFactoryBean implements FactoryBean<UserDao> {//代替原始实例工厂中创建对象的方法public UserDao getObject() throws Exception {return new UserDaoImpl();}public Class<?> getObjectType() {return UserDao.class;}}
<bean id="userDao" class="com.itheima.factory.UserDaoFactoryBean"/>

getObject() throws Exception;Class<?> getObjectType();default boolean isSingleton() {return true;}
public class AppForInstanceUser {public static void main(String[] args) {ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");UserDao userDao1 = (UserDao) ctx.getBean("userDao");UserDao userDao2 = (UserDao) ctx.getBean("userDao");System.out.println(userDao1);System.out.println(userDao2);
// userDao.save();}
}

通过验证,会发现默认是单例,那如果想改成单例具体如何实现?
public class UserDaoFactoryBean implements FactoryBean<UserDao> {public UserDao getObject() throws Exception {return new UserDaoImpl();}public Class<?> getObjectType() {return UserDao.class;}public boolean isSingleton() {return false;}}

三、bean的生命周期
- 从创建到消亡的完整过程,例如人从出生到死亡的整个过程就是一个生命周期。
- bean对象从创建到销毁的整体过程。
- 在bean创建后到销毁前做一些事情。
1.环境准备
项目结构:
(1)项目中添加BookDao、BookDaoImpl、BookService和BookServiceImpl类
public interface BookDao {public void save();
}
public class BookDaoImpl implements BookDao {
public void save() {
System.out.println("book dao save ...");
}
}
public class BookServiceImpl implements BookService{
private BookDao bookDao;
public void setBookDao(BookDao bookDao) {
this.bookDao = bookDao;
}
public void save() {
System.out.println("book service save ...");
bookDao.save();
}
}
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="bookDao" class="com.itheima.dao.impl.BookDaoImpl"/>
</beans>
public class AppForLifeCycle {public static void main( String[] args ) {ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");BookDao bookDao = (BookDao) ctx.getBean("bookDao");bookDao.save();}
}
2.生命周期设置
- bean创建之后,想要添加内容,比如用来初始化需要用到资源
- bean销毁之前,想要添加内容,比如用来释放用到的资源
步骤1:添加初始化和销毁方法
public class BookDaoImpl implements BookDao {public void save() {System.out.println("book dao save ...");}//表示bean初始化对应的操作public void init(){System.out.println("init...");}//表示bean销毁前对应的操作public void destory(){System.out.println("destory...");}}
步骤2:配置生命周期
<bean id="bookDao" class="com.itheima.dao.impl.BookDaoImpl" init-method="init" destroy-method="destory" ></bean>

- Spring的IOC容器是运行在JVM中
- 运行main方法后,JVM启动,Spring加载配置文件生成IOC容器,从容器获取bean对象,然后调方 法执行
- main方法执行完后,JVM退出,这个时候IOC容器中的bean还没有来得及销毁就已经结束了 所以没有调用对应的destroy方法
3.close关闭容器
调用ctx的close()方法
public class AppForLifeCycle {public static void main( String[] args ) {ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");BookDao bookDao = (BookDao) ctx.getBean("bookDao");bookDao.save();ctx.close();}
}

- 在容器未关闭之前,提前设置好回调函数,让JVM在退出之前回调此函数来关闭容器
- 调用ctx的registerShutdownHook()方法
public class AppForLifeCycle {public static void main( String[] args ) {ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");BookDao bookDao = (BookDao) ctx.getBean("bookDao");bookDao.save();
// 注册关闭钩子函数,在虚拟机退出之前回调此函数,关闭容器ctx.registerShutdownHook();}
}
public class BookServiceImpl implements BookService,InitializingBean,DisposableBean
{private BookDao bookDao;public void setBookDao(BookDao bookDao) {System.out.println("set .....");this.bookDao = bookDao;}public void save() {System.out.println("book service save ...");bookDao.save();}public void destroy() throws Exception {System.out.println("service destroy");}public void afterPropertiesSet() throws Exception {System.out.println("service init");}
}
<bean id="bookDao" class="com.itheima.dao.impl.BookDaoImpl" init-method="init" destroy-method="destory"/><bean id="bookService" class="com.itheima.service.impl.BookServiceImpl"><property name="bookDao" ref="bookDao"/></bean>
- 在配置文件中的bean标签中添加init-method和destroy-method属性
- 类实现InitializingBean与DisposableBean接口,这种方式了解下即可。
- 1.创建对象(内存分配)
- 2.执行构造方法
- 3.执行属性注入(set操作)
- 4.执行bean初始化方法
- 1.执行业务操作
- 1.执行bean销毁方法
- close()方法
- registerShutdownHook()方法
相关文章:

【Spring篇】IOC相关内容
🍓系列专栏:Spring系列专栏 🍉个人主页:个人主页 目录 一、bean基础配置 1.bean基础配置(id与class) 2.bean的name属性 3.bean作用范围scope配置 二、bean实例化 1.构造方法实例化 2.分析Spring的错误信息 3.静态工厂实例化 4.实例工厂 5.FactoryBean 三…...

Python超矩形
文章目录 距离函数矩形分割 Rectangle是 scipy.spatial中封装的类,其构造函数只需输入最小值和最大值的数组即可,并且可通过内置的 volume方法计算广义的体积。 from scipy.spatial import Rectanglerec Rectangle((0,0), (5,5)) print(rec.maxes) …...

【软考数据库】第五章 计算机网络
目录 5.1 网络功能和分类 5.2 OSI七层模型 5.3 TCP/IP协议 5.4 传输介质 5.5 通信方式和交换方式 5.6 IP地址 5.7 IPv6 5.8 网络规划和设计 5.9 其他考点补充 5.10 网络安全技术 5.11 网络安全协议 前言: 笔记来自《文老师软考数据库》教材精讲ÿ…...

深眸科技|深度学习、3D视觉融入机器视觉系统,实现生产数智化
随着“中国制造2025”战略加速落实,制造业生产线正在加紧向智能化、自动化和数字化转型之路迈进。而人工智能技术的兴起以及边缘算力持续提升的同时,机器视觉及其相关技术也在飞速发展,并不断渗透进工业领域,拓展应用场景的同时&a…...

DateFormat使用时需要注意:多线程下需要特殊处理
前言 工作或学习过程中难免会接触到时间(Date)相关的内容,比如String类型转为Date类型,或者Date类型转为String类型,jdk为我们提供了一套完善的日期格式化工具,DateFormat类,使用者可以使用该接…...

Packet Tracer - 研究直连路由
Packet Tracer - 研究直连路由 目标 第 1 部分:研究 IPv4 直连路由 第 2 部分:研究 IPv6 直连路由 拓扑图 背景信息 本活动中的网络已配置。 您将登录路由器并使用 show 命令发现并回答以下有关直连路由的问题。 注:用户 EXEC 密码是 c…...
大专生程序员找工作的一点小建议 知识分享 经验分享
最近呢有人在私信我 就问我说我呢是一个大专生 大专毕业 学历呢也不是很好 我但是我学的是这个计算机 这样一个专业 然后呢现在找工作找不到 就这样的一个要求 让我们呢给一些建议 当然就是私底下在网上聊吗 就会给 也相信 我的一个建议是什么样的 就是你首先你要去找工作的 首…...

PyCaret:低代码自动化的机器学习工具
PyCaret简介 随着ChatGPT和AI画图的大火,机器学习作为实现人工智能的底层技术被大众越来越多的认知,基于机器学习的产品也越来越多。传统的机器学习实现方法需要较强的编程能力和数据科学基础,这使得想零基础尝试机器学习变得非常困难。 机器…...

【Hello Network】网络编程套接字(三)
作者:小萌新 专栏:网络 作者简介:大二学生 希望能和大家一起进步 本篇博客简介:简单介绍下各种类型的Tcp协议 各种类型Tcp服务器 多进程版的TCP网络程序捕捉SIGCHLD信号让孙子进程执行任务 多线程TCP网络程序线程池版多线程TCP网络…...

3.4 只读存储器
学习目标: 学习只读存储器(ROM)的目标可以包括以下内容: 了解ROM的基本概念、分类以及适用场景。掌握ROM的电路原理、逻辑结构和读取方式。熟悉ROM的编程方式和编程工具。理解ROM与EPROM、EEPROM和闪存的区别和联系。了解ROM在计…...
从后端开发转大数据开发怎么样?
很多做后端的小伙伴,在某一个瞬间,都想转行大数据,那这种想法可行嘛? 转大数据的最初原因很简单,就是好几个同事都转了,他们的收入瞬间提高了好多,于是在同事的内推我也就跟着转了,…...

编程式导航路由跳转到当前路由(参数不变),多次执行会抛出NavigatorDuplicated的禁告错误?
重写push与replace方法 编程式导航路由跳转到当前路由(参数不变),多次执行会抛出NavigatorDuplicated的禁告错误? 路由跳转有俩种形式:声明式导航,编程式导航 声明式导航没有这类问题的,因为…...
AppArmor无内核及系统日志的问题及解决
在AppArmor中,正常情况下,一旦违反了规则,是能够在内核及系统日志中看到相关信息的。比如:在Ubuntu下正常产生的日志信息(示例)如下: kernel: [140321.028000] audit(1191433716.584:1578): t…...
本地更改配置ssh密钥和更改github网址
配置 SSH 密钥以进行身份验证,可以遵循以下步骤: 生成SSH密钥 打开 Git Bash 终端 在 Windows 上,可以打开 Git Bash 终端。通常,可以在开始菜单中搜索 Git Bash 并启动它。一旦打开了 Git Bash 终端,将进入一个基于…...

MATLAB函数封装2:QT调用封装函数
在利用MATLAB进行封装函数之后,最主要的目的是对函数进行调用,能够对矩阵运算和其他算法的运行进行快捷处理。 在有了MATLAB函数之后封装成DLL文件之后,在QT中添加动态链接库,就可以实现函数的调用过程,这个过程相对简…...

AJAX和JSON
1、什么是AJAX? AJAX(ASynchronous JavaScript And XML)异步的JavaScript 和 XML; 由Jesse James Garrett 在他的文章AJAX:A New Approoch to Web Applications中首次提出。 ajax(Web数据交互方式)_百…...
源码:SharedPreferences分析
一、持久化方式: DataStore:稳定性 MMKV:效率 SharedPreferneces 区别: 功能MMKVJetpack DataStoreSharedPreferneces是否阻塞主线程否否是是否线程安全是 是 是是否支持跨进程是否否是否类型…...

大二一个学期学这么点内容,没有概念,只有实操
如何查看所有的数据库: Show databases; 如何进入某个数据库: use xxx; 如何新进数据库: Create database jx; 如何删除数据库: Drop database jx; 如何查看所有的表格: Show tables; 如何创建数据表…...

AppWeb 身份验证绕过漏洞 (CVE-2018-8715)
当前漏洞环境部署在vulhub,当前验证环境为vulhub靶场(所有实验均为虚拟环境) 实验环境:攻击机----kali 靶机:centos7 1、进入靶场,启动环境 2、访问AppWeb控制台:http://your-ip:8080 使用用户名、密码adm…...
为什么监控摄像头画面不如手机拍摄视频画面清晰
一天和一个做餐饮的朋友吃饭聊天,他提出一个问题,几百块的监控摄像头就是纯粹做监控功能 ,视频拍摄的画面为什么还没有几百元的手机拍摄的视频画面清晰,对于此特意查了一下技术资料,整理一下,以备下次再详细…...
《Playwright:微软的自动化测试工具详解》
Playwright 简介:声明内容来自网络,将内容拼接整理出来的文档 Playwright 是微软开发的自动化测试工具,支持 Chrome、Firefox、Safari 等主流浏览器,提供多语言 API(Python、JavaScript、Java、.NET)。它的特点包括&a…...

UE5 学习系列(三)创建和移动物体
这篇博客是该系列的第三篇,是在之前两篇博客的基础上展开,主要介绍如何在操作界面中创建和拖动物体,这篇博客跟随的视频链接如下: B 站视频:s03-创建和移动物体 如果你不打算开之前的博客并且对UE5 比较熟的话按照以…...

高频面试之3Zookeeper
高频面试之3Zookeeper 文章目录 高频面试之3Zookeeper3.1 常用命令3.2 选举机制3.3 Zookeeper符合法则中哪两个?3.4 Zookeeper脑裂3.5 Zookeeper用来干嘛了 3.1 常用命令 ls、get、create、delete、deleteall3.2 选举机制 半数机制(过半机制࿰…...
五年级数学知识边界总结思考-下册
目录 一、背景二、过程1.观察物体小学五年级下册“观察物体”知识点详解:由来、作用与意义**一、知识点核心内容****二、知识点的由来:从生活实践到数学抽象****三、知识的作用:解决实际问题的工具****四、学习的意义:培养核心素养…...

MODBUS TCP转CANopen 技术赋能高效协同作业
在现代工业自动化领域,MODBUS TCP和CANopen两种通讯协议因其稳定性和高效性被广泛应用于各种设备和系统中。而随着科技的不断进步,这两种通讯协议也正在被逐步融合,形成了一种新型的通讯方式——开疆智能MODBUS TCP转CANopen网关KJ-TCPC-CANP…...
今日学习:Spring线程池|并发修改异常|链路丢失|登录续期|VIP过期策略|数值类缓存
文章目录 优雅版线程池ThreadPoolTaskExecutor和ThreadPoolTaskExecutor的装饰器并发修改异常并发修改异常简介实现机制设计原因及意义 使用线程池造成的链路丢失问题线程池导致的链路丢失问题发生原因 常见解决方法更好的解决方法设计精妙之处 登录续期登录续期常见实现方式特…...
A2A JS SDK 完整教程:快速入门指南
目录 什么是 A2A JS SDK?A2A JS 安装与设置A2A JS 核心概念创建你的第一个 A2A JS 代理A2A JS 服务端开发A2A JS 客户端使用A2A JS 高级特性A2A JS 最佳实践A2A JS 故障排除 什么是 A2A JS SDK? A2A JS SDK 是一个专为 JavaScript/TypeScript 开发者设计的强大库ÿ…...
腾讯云V3签名
想要接入腾讯云的Api,必然先按其文档计算出所要求的签名。 之前也调用过腾讯云的接口,但总是卡在签名这一步,最后放弃选择SDK,这次终于自己代码实现。 可能腾讯云翻新了接口文档,现在阅读起来,清晰了很多&…...
libfmt: 现代C++的格式化工具库介绍与酷炫功能
libfmt: 现代C的格式化工具库介绍与酷炫功能 libfmt 是一个开源的C格式化库,提供了高效、安全的文本格式化功能,是C20中引入的std::format的基础实现。它比传统的printf和iostream更安全、更灵活、性能更好。 基本介绍 主要特点 类型安全:…...
uniapp 集成腾讯云 IM 富媒体消息(地理位置/文件)
UniApp 集成腾讯云 IM 富媒体消息全攻略(地理位置/文件) 一、功能实现原理 腾讯云 IM 通过 消息扩展机制 支持富媒体类型,核心实现方式: 标准消息类型:直接使用 SDK 内置类型(文件、图片等)自…...