【Spring】Spring之启动过程源码解析
概述
我们说的Spring启动,就是构造ApplicationContext对象以及调用refresh()方法的过程。
Spring启动过程主要做了这么几件事情:
- 构造一个BeanFactory对象
- 解析配置类,得到BeanDefinition,并注册到BeanFactory中
- 解析@ComponentScan,此时就会完成扫描
- 解析@Import
- 解析@Bean
- …
- ApplicationContext支持国际化,需要初始化MessageSource对象
- ApplicationContext支持事件机制,需要初始化ApplicationEventMulticaster对象
- 把用户定义的ApplicationListener对象添加到ApplicationContext中,等Spring启动完了发布事件
- 创建非懒加载的单例Bean对象,并存在BeanFactory的单例池中
- 调用Lifecycle Bean的start()方法
- 发布ContextRefreshedEvent事件
Spring启动过程中要创建非懒加载的单例Bean对象,需要用到BeanPostProcessor,所以Spring在启动过程中需要做两件事:
- 生成默认的BeanPostProcessor对象,并添加到BeanFactory中
- AutowiredAnnotationBeanPostProcessor:处理@Autowired、@Value
- CommonAnnotationBeanPostProcessor:处理@Resource、@PostConstruct、@PreDestroy
- ApplicationContextAwareProcessor:处理ApplicationContextAware等回调
- 找到外部用户所定义的BeanPostProcessor对象(类型为BeanPostProcessor的Bean对象),并添加到BeanFactory中
BeanFactoryPostProcessor
BeanPostProcessor表示Bean的后置处理器,是用来对Bean进行加工的,类似的,BeanFactoryPostProcessor理解为BeanFactory的后置处理器,用来用对BeanFactory进行加工的。
Spring支持用户定义BeanFactoryPostProcessor的实现类Bean,来对BeanFactory进行加工,比如:
@Component
public class FireBeanFactoryPostProcessor implements BeanFactoryPostProcessor {@Overridepublic void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {BeanDefinition beanDefinition = beanFactory.getBeanDefinition("userService");// 修改BeanDefinition对象的属性值,发生在Spring启动时,创建单例Bean之前,后面创建Bean时此处的修改会生效beanDefinition.setAutowireCandidate(false);}
}
在ApplicationContext内部有一个核心的DefaultListableBeanFactory,它实现了ConfigurableListableBeanFactory和BeanDefinitionRegistry接口,所以ApplicationContext和DefaultListableBeanFactory是可以注册BeanDefinition的,但是ConfigurableListableBeanFactory是不能注册BeanDefinition的,只能获取BeanDefinition,然后做修改。
// AnnotationConfigApplicationContext继承GenericApplicationContext
public class GenericApplicationContext extends AbstractApplicationContext implements BeanDefinitionRegistry {private final DefaultListableBeanFactory beanFactory;...
}public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFactoryimplements ConfigurableListableBeanFactory, BeanDefinitionRegistry, Serializable {// ConfigurableListableBeanFactory只能获取BeanDefinition,不能注册BeanDefinition...
}
Spring提供了一个BeanFactoryPostProcessor的子接口:BeanDefinitionRegistryPostProcessor,用以注册BeanDefinition对象。
BeanDefinitionRegistryPostProcessor
public interface BeanDefinitionRegistryPostProcessor extends BeanFactoryPostProcessor {// 实现该接口并实现该方法,可以注册BeanDefinition对象void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException;}
自定义类注册BeanDefinition,例如:
@Component
public class FireBeanDefinitionRegistryPostProcessor implements BeanDefinitionRegistryPostProcessor {@Overridepublic void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {AbstractBeanDefinition beanDefinition = BeanDefinitionBuilder.genericBeanDefinition().getBeanDefinition();beanDefinition.setBeanClass(User.class);registry.registerBeanDefinition("user", beanDefinition);}@Overridepublic void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {BeanDefinition beanDefinition = beanFactory.getBeanDefinition("userService");beanDefinition.setAutowireCandidate(false);}
}
refresh()
构造ApplicationContext对象时,调用refresh()方法,如下:
public AnnotationConfigApplicationContext(Class<?>... componentClasses) {// 构造DefaultListableBeanFactory、AnnotatedBeanDefinitionReader、ClassPathBeanDefinitionScannerthis();register(componentClasses);refresh();
}
refresh()是在接口ConfigurableApplicationContext中定义的,如下:
public interface ConfigurableApplicationContext extends ApplicationContext, Lifecycle, Closeable {/*** Load or refresh the persistent representation of the configuration, which* might be from Java-based configuration, an XML file, a properties file, a* relational database schema, or some other format.* <p>As this is a startup method, it should destroy already created singletons* if it fails, to avoid dangling resources. In other words, after invocation* of this method, either all or no singletons at all should be instantiated.* @throws BeansException if the bean factory could not be initialized* @throws IllegalStateException if already initialized and multiple refresh* attempts are not supported*/void refresh() throws BeansException, IllegalStateException;
}
注释意思是:加载或刷新持久化的配置,可能是XML文件、属性文件或关系数据库中存储的。由于这是一个启动方法,如果失败,它应该销毁已经创建的单例,以避免占用资源。换句话说,在调用该方法之后,应该实例化所有的单例,或者根本不实例化单例 。
注意:ApplicationContext关闭之后不代表JVM也关闭了,ApplicationContext是属于JVM的,说白了ApplicationContext也是JVM中的一个对象。
有两种ApplicationContext,分为可刷新和不可刷新(只能刷新一次,不能重复刷新),如下:
// 刷新的ApplicationContext
AbstractRefreshableApplicationContext extends AbstractApplicationContext
// 不可刷新的ApplicationContext
GenericApplicationContext extends AbstractApplicationContext
AnnotationConfigApplicationContext继承的是GenericApplicationContext,所以它是不能刷新的。
AnnotationConfigWebApplicationContext继承的是AbstractRefreshableWebApplicationContext,所以它是可以刷新的。
下面以AnnotationConfigApplicationContext为例子,来介绍refresh的底层实现流程:
- 在调用AnnotationConfigApplicationContext的构造方法之前,会调用父类GenericApplicationContext的无参构造方法,会构造一个BeanFactory,为DefaultListableBeanFactory
- 构造AnnotatedBeanDefinitionReader(主要作用添加一些基础的PostProcessor,同时可以通过reader进行BeanDefinition的注册),同时对BeanFactory进行设置和添加PostProcessor(后置处理器)
- 设置dependencyComparator:AnnotationAwareOrderComparator,它是一个Comparator,是用来进行排序的,会获取某个对象上的Order注解或者通过实现Ordered接口所定义的值进行排序,在日常开发中可以利用这个类来进行排序
- 设置autowireCandidateResolver:ContextAnnotationAutowireCandidateResolver,用来解析某个Bean能不能进行自动注入,比如某个Bean的autowireCandidate属性是否等于true
- 向BeanFactory中添加ConfigurationClassPostProcessor对应的BeanDefinition,它是一个BeanDefinitionRegistryPostProcessor,并且实现了PriorityOrdered接口
- 向BeanFactory中添加AutowiredAnnotationBeanPostProcessor对应的BeanDefinition,它是一个InstantiationAwareBeanPostProcessorAdapter,MergedBeanDefinitionPostProcessor
- 向BeanFactory中添加CommonAnnotationBeanPostProcessor对应的BeanDefinition,它是一个InstantiationAwareBeanPostProcessor,InitDestroyAnnotationBeanPostProcessor
- 向BeanFactory中添加EventListenerMethodProcessor对应的BeanDefinition,它是一个BeanFactoryPostProcessor,SmartInitializingSingleton
- 向BeanFactory中添加DefaultEventListenerFactory对应的BeanDefinition,它是一个EventListenerFactory
- 构造ClassPathBeanDefinitionScanner(主要作用可以用来扫描得到并注册BeanDefinition),同时进行设置:
- 设置this.includeFilters = AnnotationTypeFilter(Component.class)
- 设置environment
- 设置resourceLoader
- 利用reader注册AppConfig为BeanDefinition,类型为AnnotatedGenericBeanDefinition
- 接下来就是调用refresh方法
- prepareRefresh():
- 记录启动时间
- 可以允许子容器设置一些内容到Environment中
- 验证Environment中是否包括了必须要有的属性
- obtainFreshBeanFactory():进行BeanFactory的refresh,在这里会去调用子类的refreshBeanFactory方法,具体子类是怎么刷新的得看子类,然后再调用子类的getBeanFactory方法,重新得到一个BeanFactory
- prepareBeanFactory(beanFactory):
- 设置beanFactory的类加载器
- 设置表达式解析器:StandardBeanExpressionResolver,用来解析Spring中的表达式
- 添加PropertyEditorRegistrar:ResourceEditorRegistrar,PropertyEditor类型转化器注册器,用来注册一些默认的PropertyEditor
- 添加一个Bean的后置处理器:ApplicationContextAwareProcessor,是一个BeanPostProcessor,用来执行EnvironmentAware、ApplicationEventPublisherAware等回调方法
- 添加ignoredDependencyInterface:可以向这个属性中添加一些接口,如果某个类实现了这个接口,并且这个类中的某些set方法在接口中也存在,那么这个set方法在自动注入的时候是不会执行的,比如EnvironmentAware这个接口,如果某个类实现了这个接口,那么就必须实现它的setEnvironment方法,而这是一个set方法,和Spring中的autowire是冲突的,那么Spring在自动注入时是不会调用setEnvironment方法的,而是等到回调Aware接口时再来调用(注意,这个功能仅限于xml的autowire,@Autowired注解是忽略这个属性的)
- EnvironmentAware
- EmbeddedValueResolverAware
- ResourceLoaderAware
- ApplicationEventPublisherAware
- MessageSourceAware
- ApplicationContextAware
- 另外其实在构造BeanFactory的时候就已经提前添加了另外三个:
- BeanNameAware
- BeanClassLoaderAware
- BeanFactoryAware
- 添加resolvableDependencies:在byType进行依赖注入时,会先从这个属性中根据类型找bean
- BeanFactory.class:当前BeanFactory对象
- ResourceLoader.class:当前ApplicationContext对象
- ApplicationEventPublisher.class:当前ApplicationContext对象
- ApplicationContext.class:当前ApplicationContext对象
- 添加一个Bean的后置处理器:ApplicationListenerDetector,是一个BeanPostProcessor,用来判断某个Bean是不是ApplicationListener,如果是则把这个Bean添加到ApplicationContext中去,注意一个ApplicationListener只能是单例的
- 添加一个Bean的后置处理器:LoadTimeWeaverAwareProcessor,是一个BeanPostProcessor,用来判断某个Bean是不是实现了LoadTimeWeaverAware接口,如果实现了则把ApplicationContext中的loadTimeWeaver回调setLoadTimeWeaver方法设置给该Bean
- 添加一些单例bean到单例池:
- “environment”:Environment对象
- “systemProperties”:System.getProperties()返回的Map对象
- “systemEnvironment”:System.getenv()返回的Map对象
- postProcessBeanFactory(beanFactory) : 提供给AbstractApplicationContext的子类进行扩展,具体的子类,可以继续向BeanFactory中再添加一些东西
- invokeBeanFactoryPostProcessors(beanFactory):执行BeanFactoryPostProcessor
- 此时在BeanFactory中会存在一个BeanFactoryPostProcessor:ConfigurationClassPostProcessor,它也是一个BeanDefinitionRegistryPostProcessor
- 第一阶段
- 从BeanFactory中找到类型为BeanDefinitionRegistryPostProcessor的beanName,也就是ConfigurationClassPostProcessor, 然后调用BeanFactory的getBean方法得到实例对象
- 执行**ConfigurationClassPostProcessor的postProcessBeanDefinitionRegistry()**方法:
- 解析AppConfig类
- 扫描得到BeanDefinition并注册
- 解析@Import,@Bean等注解得到BeanDefinition并注册
- 详细的看另外的笔记,专门分析了ConfigurationClassPostProcessor是如何工作的
- 在这里,我们只需要知道在这一步会去得到BeanDefinition,而这些BeanDefinition中可能存在BeanFactoryPostProcessor和BeanDefinitionRegistryPostProcessor,所以执行完ConfigurationClassPostProcessor的postProcessBeanDefinitionRegistry()方法后,还需要继续执行其他BeanDefinitionRegistryPostProcessor的postProcessBeanDefinitionRegistry()方法
- 执行其他BeanDefinitionRegistryPostProcessor的**postProcessBeanDefinitionRegistry()**方法
- 执行所有BeanDefinitionRegistryPostProcessor的**postProcessBeanFactory()**方法
- 第二阶段
- 从BeanFactory中找到类型为BeanFactoryPostProcessor的beanName,而这些BeanFactoryPostProcessor包括了上面的BeanDefinitionRegistryPostProcessor
- 执行还没有执行过的BeanFactoryPostProcessor的**postProcessBeanFactory()**方法
- 到此,所有的BeanFactoryPostProcessor的逻辑都执行完了,主要做的事情就是得到BeanDefinition并注册到BeanFactory中
- registerBeanPostProcessors(beanFactory):因为上面的步骤完成了扫描,这个过程中程序员可能自己定义了一些BeanPostProcessor,在这一步就会把BeanFactory中所有的BeanPostProcessor找出来并实例化得到一个对象,并添加到BeanFactory中去(属性beanPostProcessors),最后再重新添加一个ApplicationListenerDetector对象(之前其实就添加了过,这里是为了把ApplicationListenerDetector移动到最后)
- initMessageSource():如果BeanFactory中存在一个叫做"messageSource"的BeanDefinition,那么就会把这个Bean对象创建出来并赋值给ApplicationContext的messageSource属性,让ApplicationContext拥有国际化的功能
- initApplicationEventMulticaster():如果BeanFactory中存在一个叫做"applicationEventMulticaster"的BeanDefinition,那么就会把这个Bean对象创建出来并赋值给ApplicationContext的applicationEventMulticaster属性,让ApplicationContext拥有事件发布的功能
- onRefresh():提供给AbstractApplicationContext的子类进行扩展,没用
- registerListeners():从BeanFactory中获取ApplicationListener类型的beanName,然后添加到ApplicationContext中的事件广播器applicationEventMulticaster中去,到这一步因为FactoryBean还没有调用getObject()方法生成Bean对象,所以这里要在根据类型找一下ApplicationListener,记录一下对应的beanName
- finishBeanFactoryInitialization(beanFactory):完成BeanFactory的初始化,主要就是实例化非懒加载的单例Bean
- finishRefresh():BeanFactory的初始化完后,就到了Spring启动的最后一步了
- 设置ApplicationContext的lifecycleProcessor,默认情况下设置的是DefaultLifecycleProcessor
- 调用lifecycleProcessor的onRefresh()方法,如果是DefaultLifecycleProcessor,那么会获取所有类型为Lifecycle的Bean对象,然后调用它的start()方法,这就是ApplicationContext的生命周期扩展机制
- 发布ContextRefreshedEvent事件
BeanFactoryPostProcessor
执行各个BeanDefinitionRegistryPostProcessor流程:
- 执行通过ApplicationContext添加进来的BeanDefinitionRegistryPostProcessor的**postProcessBeanDefinitionRegistry()**方法
- 执行BeanFactory中实现了PriorityOrdered接口的BeanDefinitionRegistryPostProcessor的**postProcessBeanDefinitionRegistry()**方法
- 执行BeanFactory中实现了Ordered接口的BeanDefinitionRegistryPostProcessor的**postProcessBeanDefinitionRegistry()**方法
- 执行BeanFactory中其他的BeanDefinitionRegistryPostProcessor的**postProcessBeanDefinitionRegistry()**方法
- 执行上面所有的BeanDefinitionRegistryPostProcessor的**postProcessBeanFactory()**方法
- 执行通过ApplicationContext添加进来的BeanFactoryPostProcessor的**postProcessBeanFactory()**方法
- 执行BeanFactory中实现了PriorityOrdered接口的BeanFactoryPostProcessor的**postProcessBeanFactory()**方法
- 执行BeanFactory中实现了Ordered接口的BeanFactoryPostProcessor的**postProcessBeanFactory()**方法
- 执行BeanFactory中其他的BeanFactoryPostProcessor的**postProcessBeanFactory()**方法
Lifecycle接口
Lifecycle表示的是ApplicationContext的生命周期,可以定义一个SmartLifecycle来监听ApplicationContext的启动和关闭,如下:
@Component
public class FireLifecycle implements SmartLifecycle {private boolean isRunning = false;@Overridepublic void start() {System.out.println("启动");isRunning = true;}@Overridepublic void stop() {// 要触发stop(),要调用context.close(),或者注册关闭钩子(context.registerShutdownHook();)System.out.println("停止");isRunning = false;}@Overridepublic boolean isRunning() {return isRunning;}
}
相关文章:
【Spring】Spring之启动过程源码解析
概述 我们说的Spring启动,就是构造ApplicationContext对象以及调用refresh()方法的过程。 Spring启动过程主要做了这么几件事情: 构造一个BeanFactory对象解析配置类,得到BeanDefinition,并注册到BeanFactory中 解析ComponentS…...
状态模式(State)
状态模式是一种行为设计模式,允许一个对象在其内部状态改变时改变它的行为,使其看起来修改了自身所属的类。其别名为状态对象(Objects for States)。 State is a behavior design pattern that allows an object to change its behavior when its inter…...
【uniapp】样式合集
1、修改uni-data-checkbox多选框的样式为单选框的样式 我原先是用的单选,但是单选并不支持选中后,再次点击取消选中;所以我改成了多选,然后改变多选样式,让他看起来像单选 在所在使用的页面上修改样式即可 <uni-d…...
【Spring框架】SpringBoot统一功能处理
目录 用户登录权限校验用户登录拦截器排除所有静态资源练习:登录拦截器拦截器实现原理 统一异常处理统一数据返回格式为什么需要统⼀数据返回格式?统⼀数据返回格式的实现 用户登录权限校验 用户登录拦截器 1.自定义拦截器 package com.example.demo.…...
51单片机学习--按键控制流水灯模式定时器时钟
TMOD负责确定T0和T1的工作模式,TCON控制T0和T1的启动或停止计数,同时包含定时器状态 TF1:定时器1溢出标志 TF0:定时器0溢出标志 0~65535 每隔1微秒计数器1,总时间65535微秒,赋上初值64535,则只…...
Django教程_编程入门自学教程_菜鸟教程-免费教程分享
教程简介 Django是一个开放源代码的Web应用框架,由Python写成。采用了MTV的框架模式,即模型M,视图V和模版T。它最初是被开发来用于管理劳伦斯出版集团旗下的一些以新闻内容为主的网站的,即是CMS(内容管理系统…...
VGG卷积神经网络-笔记
VGG卷积神经网络-笔记 VGG是当前最流行的CNN模型之一, 2014年由Simonyan和Zisserman提出, 其命名来源于论文作者所在的实验室Visual Geometry Group。 测试结果为: 通过运行结果可以发现,在眼疾筛查数据集iChallenge-PM上使用VGG…...
Python爬虫如何实现IP代理池搭建
大家好,作为一名IP代理产品供应商,我知道很多人在使用Python爬虫时遇到了一些麻烦。有时候,我们的爬虫在爬取过程中会被目标网站识别并封禁IP,导致我们的爬取任务受阻。今天我要分享的就是如何搭建一个高效稳定的IP代理池…...
单例模式:保证一个类只有一个实例
单例模式:保证一个类只有一个实例 什么是单例模式? 在软件开发中,有些类只需要一个实例,比如数据库连接池、线程池等。单例模式就是一种设计模式,用于确保一个类只有一个实例,并提供一个全局访问点。 实…...
【新版系统架构补充】-七层模型
网络功能和分类 计算网络的功能 :数据通信、资源共享、管理集中化、实现分布式处理、负载均衡 网络性能指标:速率、带宽(频带宽度或传送线路速率)、吞吐量、时延、往返时间、利用率 网络非性能指标:费用、质量、标准化…...
第2章 C语言概述
本章介绍以下内容: 运算符: 函数:main()、printf() 编写一个简单的C程序 创建整型变量,为其赋值并在屏幕上显示其值 换行字符 如何在程序中写注释,创建包含多个函数的程序,发现程序的错误 什么是关键字 C程…...
vscode vue3开发常用插件(附Prettier格式化配置)
必不可少插件(名称可能不全): 1、Chinese (Simplified) (简体中文) Language 2、Prettier - Code formatter 3、Vue 3 Snippets 4、Vue Language Features (Volar) 可选插件: 5、Auto Close Tag 6、Vue Theme Prettier格式化配置: 按ctr…...
【微信小程序】van-uploader实现文件上传
使用van-uploader和wx.uploadFile实现文件上传,后端使用ThinkPHP。 1、前端代码 json:引入van-uploader {"usingComponents": {"van-uploader": "vant/weapp/uploader/index"} }wxml:deletedFile是删除文件函…...
人工智能在计算机视觉中的应用与挑战
引言 计算机视觉是人工智能领域的一个重要分支,旨在让计算机能够像人一样理解和解释视觉信息,实现图像和视频的自动识别、理解和分析。计算机视觉技术已经在许多领域产生了深远的影响,如人脸识别、自动驾驶、医学影像分析等。本篇博客将深入…...
以太网接口指示灯状态分析和电路设计
一、RJ45以太网连接器介绍 以带网络隔离变压器的RJ45接头为例,如HR911105A,其技术参数如下 原理框图 指示灯部分 二、PHY芯片 phy芯片以DP83848CVV/NOPB为例,查看数据手册。引脚26,引脚27和引脚28和LED灯相关,如下截…...
Redis的基础
一、进入redis 内部 / 关闭 # 方式一: // 进入redis redis-cli // 有密码输入密码 :auth [username] password auth 123456 # 方式二: // 进入redis 并且输入密码 redis-cli -a 123456// 如果在docker 里面的则可以 docker exec -it redis…...
LeetCode 626. 换座位
题目链接:LeetCode 626. 换座位 题目描述 表名:Seat 编写SQL查询来交换每两个连续的学生的座位号。如果学生的数量是奇数,则最后一个学生的id不交换。 按 id 升序 返回结果表。 查询结果格式如下所示。 示例1: 题目分析 如…...
华为、阿里巴巴、字节跳动 100+ Python 面试问题总结(六)
系列文章目录 个人简介:机电专业在读研究生,CSDN内容合伙人,博主个人首页 Python面试专栏:《Python面试》此专栏面向准备面试的2024届毕业生。欢迎阅读,一起进步!🌟🌟🌟 …...
hash 模式和 history 模式的实现原理
hash 模式和 history 模式的实现原理: #后面的 hash 值的变化不会导致浏览器向服务器发出请求,浏览器不发出请求,就不会刷新页面。通过监听 hashchange 事件的变化可以知道 hash 值发生了哪些变化,然后根据 hash 值的变化来实现更…...
并发编程Part 2
1. JMM 问题:请你谈谈你对volatile的理解? volitile 是 Java 虚拟机提供的一种轻量级的同步机制 ,三大特性: 保证可见性 不保证原子性 禁止指令重排 线程之间如何通信? 通信是指线程之间以如何来交换信息。一般线程之间的通信…...
地震勘探——干扰波识别、井中地震时距曲线特点
目录 干扰波识别反射波地震勘探的干扰波 井中地震时距曲线特点 干扰波识别 有效波:可以用来解决所提出的地质任务的波;干扰波:所有妨碍辨认、追踪有效波的其他波。 地震勘探中,有效波和干扰波是相对的。例如,在反射波…...
(二)原型模式
原型的功能是将一个已经存在的对象作为源目标,其余对象都是通过这个源目标创建。发挥复制的作用就是原型模式的核心思想。 一、源型模式的定义 原型模式是指第二次创建对象可以通过复制已经存在的原型对象来实现,忽略对象创建过程中的其它细节。 📌 核心特点: 避免重复初…...
【RockeMQ】第2节|RocketMQ快速实战以及核⼼概念详解(二)
升级Dledger高可用集群 一、主从架构的不足与Dledger的定位 主从架构缺陷 数据备份依赖Slave节点,但无自动故障转移能力,Master宕机后需人工切换,期间消息可能无法读取。Slave仅存储数据,无法主动升级为Master响应请求ÿ…...
CMake控制VS2022项目文件分组
我们可以通过 CMake 控制源文件的组织结构,使它们在 VS 解决方案资源管理器中以“组”(Filter)的形式进行分类展示。 🎯 目标 通过 CMake 脚本将 .cpp、.h 等源文件分组显示在 Visual Studio 2022 的解决方案资源管理器中。 ✅ 支持的方法汇总(共4种) 方法描述是否推荐…...
Go 语言并发编程基础:无缓冲与有缓冲通道
在上一章节中,我们了解了 Channel 的基本用法。本章将重点分析 Go 中通道的两种类型 —— 无缓冲通道与有缓冲通道,它们在并发编程中各具特点和应用场景。 一、通道的基本分类 类型定义形式特点无缓冲通道make(chan T)发送和接收都必须准备好࿰…...
SQL Server 触发器调用存储过程实现发送 HTTP 请求
文章目录 需求分析解决第 1 步:前置条件,启用 OLE 自动化方式 1:使用 SQL 实现启用 OLE 自动化方式 2:Sql Server 2005启动OLE自动化方式 3:Sql Server 2008启动OLE自动化第 2 步:创建存储过程第 3 步:创建触发器扩展 - 如何调试?第 1 步:登录 SQL Server 2008第 2 步…...
深度解析:etcd 在 Milvus 向量数据库中的关键作用
目录 🚀 深度解析:etcd 在 Milvus 向量数据库中的关键作用 💡 什么是 etcd? 🧠 Milvus 架构简介 📦 etcd 在 Milvus 中的核心作用 🔧 实际工作流程示意 ⚠️ 如果 etcd 出现问题会怎样&am…...
Java多线程实现之Runnable接口深度解析
Java多线程实现之Runnable接口深度解析 一、Runnable接口概述1.1 接口定义1.2 与Thread类的关系1.3 使用Runnable接口的优势 二、Runnable接口的基本实现方式2.1 传统方式实现Runnable接口2.2 使用匿名内部类实现Runnable接口2.3 使用Lambda表达式实现Runnable接口 三、Runnabl…...
验证redis数据结构
一、功能验证 1.验证redis的数据结构(如字符串、列表、哈希、集合、有序集合等)是否按照预期工作。 2、常见的数据结构验证方法: ①字符串(string) 测试基本操作 set、get、incr、decr 验证字符串的长度和内容是否正…...
C#最佳实践:为何优先使用as或is而非强制转换
C#最佳实践:为何优先使用as或is而非强制转换 在 C# 的编程世界里,类型转换是我们经常会遇到的操作。就像在现实生活中,我们可能需要把不同形状的物品重新整理归类一样,在代码里,我们也常常需要将一个数据类型转换为另…...
