【Spring Boot 源码学习】OnBeanCondition 详解

Spring Boot 源码学习系列

在这里插入图片描述

OnBeanCondition 详解

  • 引言
  • 往期内容
  • 主要内容
    • 1. getOutcomes 方法
    • 2. getMatchOutcome 方法
      • 2.1 ConditionalOnBean 注解处理
      • 2.2 ConditionalOnSingleCandidate 注解处理
      • 2.3 ConditionalOnMissingBean 注解处理
    • 3. getMatchingBeans 方法
  • 总结

引言

上篇博文带大家从 Spring Boot 源码深入详解了 OnClassCondition,那本篇也同样从源码入手,带大家深入了解 OnBeanCondition 的过滤匹配实现。

往期内容

在开始本篇的内容介绍之前,我们先来看看往期的系列文章【有需要的朋友,欢迎关注系列专栏】:

Spring Boot 源码学习
Spring Boot 项目介绍
Spring Boot 核心运行原理介绍
【Spring Boot 源码学习】@EnableAutoConfiguration 注解
【Spring Boot 源码学习】@SpringBootApplication 注解
【Spring Boot 源码学习】走近 AutoConfigurationImportSelector
【Spring Boot 源码学习】自动装配流程源码解析(上)
【Spring Boot 源码学习】自动装配流程源码解析(下)
【Spring Boot 源码学习】深入 FilteringSpringBootCondition
【Spring Boot 源码学习】OnClassCondition 详解

主要内容

话不多说,马上进入正题,我们开始本篇的内容,重点详解 OnBeanCondition 的实现。

在这里插入图片描述

1. getOutcomes 方法

OnBeanCondition 同样也是 FilteringSpringBootCondition 的子类,我们依旧是从 getOutcomes 方法源码来分析【Spring Boot 2.7.9】:

@Order(Ordered.LOWEST_PRECEDENCE)
class OnBeanCondition extends FilteringSpringBootCondition implements ConfigurationCondition {// ...@Overrideprotected final ConditionOutcome[] getOutcomes(String[] autoConfigurationClasses,AutoConfigurationMetadata autoConfigurationMetadata) {ConditionOutcome[] outcomes = new ConditionOutcome[autoConfigurationClasses.length];for (int i = 0; i < outcomes.length; i++) {String autoConfigurationClass = autoConfigurationClasses[i];if (autoConfigurationClass != null) {Set<String> onBeanTypes = autoConfigurationMetadata.getSet(autoConfigurationClass, "ConditionalOnBean");outcomes[i] = getOutcome(onBeanTypes, ConditionalOnBean.class);if (outcomes[i] == null) {Set<String> onSingleCandidateTypes = autoConfigurationMetadata.getSet(autoConfigurationClass,"ConditionalOnSingleCandidate");outcomes[i] = getOutcome(onSingleCandidateTypes, ConditionalOnSingleCandidate.class);}}}return outcomes;}// ...
}

上述 getOutcomes 方法中针对 自动配置数据的循环处理逻辑,大致可总结为如下两种:

  • 通过调用 AutoConfigurationMetadata 接口的 get(String className, String key) 方法来获取与autoConfigurationClass 关联的名为 "ConditionalOnBean" 的条件属性值,可能含多个,存入 Set 集合 onBeanTypes 变量中;接着调用 getOutcome(Set<String> requiredBeanTypes, Class<? extends Annotation> annotation) 方法来获取过滤匹配结果,并赋值给 outcomes[i]

    我们以 RedisCacheConfiguration 为例,可以看到如下配置:
    在这里插入图片描述

  • 如果上述过滤匹配结果 outcomes[i]null,则通过调用 AutoConfigurationMetadata 接口的 get(String className, String key) 方法来获取与autoConfigurationClass 关联的名为 "ConditionalOnSingleCandidate" 的条件属性值,可能含多个,存入 Set 集合 onSingleCandidateTypes 变量中;接着调用 getOutcome(Set<String> requiredBeanTypes, Class<? extends Annotation> annotation) 方法来获取过滤匹配结果,并赋值给 outcomes[i]

    我们以 MongoDatabaseFactoryConfiguration 为例,可以看到如下配置:
    在这里插入图片描述

有关 AutoConfigurationMetadata 接口的 get(String className, String key) 方法的逻辑,请查看 Huazie 的 上一篇博文【Spring Boot 源码学习】OnClassCondition 详解,这里不再赘述。

下面我们继续查看 getOutcome(Set<String> requiredBeanTypes, Class<? extends Annotation> annotation) 方法的逻辑:

private ConditionOutcome getOutcome(Set<String> requiredBeanTypes, Class<? extends Annotation> annotation) {List<String> missing = filter(requiredBeanTypes, ClassNameFilter.MISSING, getBeanClassLoader());if (!missing.isEmpty()) {ConditionMessage message = ConditionMessage.forCondition(annotation).didNotFind("required type", "required types").items(Style.QUOTE, missing);return ConditionOutcome.noMatch(message);}return null;
}

进入 getOutcome 方法,可以看到:

  • 首先调用父类 FilteringSpringBootCondition 中的 filter 方法,来获取给定的类集合 requiredBeanTypes 中加载失败的类集合 missing【即当前类加载器中不存在的类集合】;
  • 如果 missing 不为空,说明存在加载失败的类,则返回 不满足过滤匹配的结果【即 ConditionOutcome.noMatch,其中没有找到 missing 中需要的类型】;
  • 如果 missing 为空,直接返回 null 即可。

2. getMatchOutcome 方法

OnClassCondition 一样,OnBeanCondition 同样实现了 FilteringSpringBootCondition 的父类 SpringBootCondition 中的抽象方法 getMatchOutcome 方法。

有关 SpringBootCondition 的介绍,这里不赘述了,请查看笔者的 【Spring Boot 源码学习】OnClassCondition 详解。

通过查看 getMatchOutcome 方法源码,可以看到针对 ConditionalOnBean 注解、ConditionalOnSingleCandidate 注解 和 ConditionalOnMissingBean 注解的三块处理逻辑,下面来一一讲解:

@Override
public ConditionOutcome getMatchOutcome(ConditionContext context, AnnotatedTypeMetadata metadata) {ConditionMessage matchMessage = ConditionMessage.empty();MergedAnnotations annotations = metadata.getAnnotations();// ConditionalOnBean 注解处理// ConditionalOnSingleCandidate 注解处理// ConditionalOnMissingBean 注解处理return ConditionOutcome.match(matchMessage);
}

2.1 ConditionalOnBean 注解处理

我们来看看 ConditionalOnBean 注解处理逻辑的源码:

	if (annotations.isPresent(ConditionalOnBean.class)) {Spec<ConditionalOnBean> spec = new Spec<>(context, metadata, annotations, ConditionalOnBean.class);MatchResult matchResult = getMatchingBeans(context, spec);if (!matchResult.isAllMatched()) {String reason = createOnBeanNoMatchReason(matchResult);return ConditionOutcome.noMatch(spec.message().because(reason));}matchMessage = spec.message(matchMessage).found("bean", "beans").items(Style.QUOTE, matchResult.getNamesOfAllMatches());}

针对上述代码,且听分析如下:

  • 首先调用 MergedAnnotations 接口的 isPresent(Class<A> annotationType) 方法判断指定的注解类型是直接存在或者元存在【这里相当于调用 get(annotationType).isPresent()】,如果返回 true,表示存在指定的注解类型。
  • 如果存在 @ConditionalOnBean,则
    • 创建一个条件规范 Spec 对象,该类是从底层的注解中提取的搜索规范;
    • 接着,调用 getMatchingBeans 方法,并从上下文【context】中获取与条件规范【spec】匹配的 Spring Beans 的结果【MatchResult】;
    • 然后,检查匹配结果,如果不是所有的条件都匹配,则继续如下:
      • 调用 createOnBeanNoMatchReason 方法,创建一个描述条件不匹配原因的字符串并返回;
      • 返回一个表示未匹配条件的 ConditionOutcome 对象【其中包含了条件规范的消息以及不匹配的原因】;
    • 否则,更新匹配消息,并记录 找到了所有匹配的 Spring Beans

2.2 ConditionalOnSingleCandidate 注解处理

我们继续查看 ConditionalOnSingleCandidate 注解处理逻辑的源码:

	if (metadata.isAnnotated(ConditionalOnSingleCandidate.class.getName())) {Spec<ConditionalOnSingleCandidate> spec = new SingleCandidateSpec(context, metadata, annotations);MatchResult matchResult = getMatchingBeans(context, spec);if (!matchResult.isAllMatched()) {return ConditionOutcome.noMatch(spec.message().didNotFind("any beans").atAll());}Set<String> allBeans = matchResult.getNamesOfAllMatches();if (allBeans.size() == 1) {matchMessage = spec.message(matchMessage).found("a single bean").items(Style.QUOTE, allBeans);}else {List<String> primaryBeans = getPrimaryBeans(context.getBeanFactory(), allBeans,spec.getStrategy() == SearchStrategy.ALL);if (primaryBeans.isEmpty()) {return ConditionOutcome.noMatch(spec.message().didNotFind("a primary bean from beans").items(Style.QUOTE, allBeans));}if (primaryBeans.size() > 1) {return ConditionOutcome.noMatch(spec.message().found("multiple primary beans").items(Style.QUOTE, primaryBeans));}matchMessage = spec.message(matchMessage).found("a single primary bean '" + primaryBeans.get(0) + "' from beans").items(Style.QUOTE, allBeans);}}

同样针对上述代码,跟着 Huazie 来一步步分析下:

  • 首先调用 AnnotatedTypeMetadata 接口的 isAnnotated(String annotationName) 方法判断元数据中是否存在指定注解。如果返回 true,表示元数据中存在指定注解。
  • 如果元数据中存在 @ConditionalOnSingleCandidate 注解,则
    • 创建了一个 SingleCandidateSpec 的对象 spec ,并传入上下文 【context】、元数据 【metadata】 和注解信息 【annotations】 ,该类是专门针对 @ConditionalOnSingleCandidate 注解的条件规范。
    • 接着调用 getMatchingBeans 方法对 context 中的所有 bean 进行匹配,并将与条件规范【spec】匹配的 Spring Beans 的结果存储在 matchResult 变量中;
    • 如果没有匹配的 bean,则返回表示未匹配条件的 ConditionOutcome 对象【其中记录了 没有找到任何 bean 的信息】;
    • 否则,获取匹配的所有 bean 名称并存储在 allBeans 变量中。
      • 如果仅有一个匹配的 bean,则更新匹配消息,并记录找到了 单个 bean 的信息;
      • 否则,获取首选 bean 名称列表,并检查列表是否为空;
        • 如果列表为空,则返回表示未匹配条件的 ConditionOutcome 对象【其中记录了 一个首选 bean 也没有找到 的信息】;
        • 如果首选 bean 名称列表包含多个 bean,则返回表示未匹配条件的 ConditionOutcome 对象【其中记录了 找到了多个首选 bean 的信息】;
        • 否则,更新匹配消息,并记录 找到了首选 bean 的信息。

2.3 ConditionalOnMissingBean 注解处理

我们继续查看 ConditionalOnMissingBean 注解处理逻辑的源码:

	if (metadata.isAnnotated(ConditionalOnMissingBean.class.getName())) {Spec<ConditionalOnMissingBean> spec = new Spec<>(context, metadata, annotations,ConditionalOnMissingBean.class);MatchResult matchResult = getMatchingBeans(context, spec);if (matchResult.isAnyMatched()) {String reason = createOnMissingBeanNoMatchReason(matchResult);return ConditionOutcome.noMatch(spec.message().because(reason));}matchMessage = spec.message(matchMessage).didNotFind("any beans").atAll();}

经过上述两种处理逻辑的分析,相信大家应该可以看懂第三种处理逻辑的分析:

  • 首先调用 AnnotatedTypeMetadata 接口的 isAnnotated(String annotationName) 方法判断元数据中是否存在指定注解。如果返回 true,表示元数据中存在指定注解。
  • 如果存在 @ConditionalOnMissingBean 注解,则
    • 创建一个条件规范 Spec 对象,该类是从底层的注解中提取的搜索规范;
    • 接着,调用 getMatchingBeans 方法,并从上下文【context】中获取与条件规范【spec】匹配的 Spring Beans 的结果【MatchResult】;
    • 如果存在任何一个匹配的 bean,则
      • 调用 createOnMissingBeanNoMatchReason 方法,创建一个描述条件不匹配原因的字符串并返回;
      • 返回一个表示未匹配条件的 ConditionOutcome 对象【其中包含了条件规范的消息以及不匹配的原因】;
    • 否则,更新匹配消息,并记录 找不到指定类型的 bean 的信息。

3. getMatchingBeans 方法

上述三种注解处理逻辑中,我们都看到了调用 getMatchingBeans 方法,下面重点来讲解一下:

protected final MatchResult getMatchingBeans(ConditionContext context, Spec<?> spec) {// ...
}

我们可以看到 getMatchingBeans 方法,有两个参数,它们分别是 上下文 【context】和 条件规范【spec】;

继续看 getMatchingBeans 方法内部逻辑:

	ClassLoader classLoader = context.getClassLoader();ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();

这里从上下文【context】中获取 ClassLoaderConfigurableListableBeanFactory

知识拓展:

  • ClassLoaderJava 中的一个接口,用于加载类。它是 Java 类加载机制的核心部分,负责将 .class 文件转换为 Java 类实例。ClassLoader 可以从不同的来源(如文件系统、网络、数据库等)加载类,也可以实现自定义的类加载逻辑。
  • ConfigurableListableBeanFactorySpring 框架中的一个核心接口,它扩展了ListableBeanFactory 接口,提供了更多的配置和扩展功能。它是一个 bean 工厂的抽象概念,用于管理 Spring 容器中的 bean 对象。ConfigurableListableBeanFactory 提供了添加、移除、注册和查找 bean 的方法,以及设置和获取 bean 属性值的功能。它还支持bean 的后处理和事件传播。
	boolean considerHierarchy = spec.getStrategy() != SearchStrategy.CURRENT;

这里根据 Spec 对象的 SearchStrategy 属性来确定是否考虑 bean 的层次结构。如果SearchStrategyCURRENT【】,则不考虑层次结构【即 considerHierarchy 为 false】;否则,考虑层次结构【即 considerHierarchy 为 true】。

	Set<Class<?>> parameterizedContainers = spec.getParameterizedContainers();

这里获取 Spec 对象的 parameterizedContainers 属性,这是一个包含参数化容器类型的集合

	if (spec.getStrategy() == SearchStrategy.ANCESTORS) {BeanFactory parent = beanFactory.getParentBeanFactory();Assert.isInstanceOf(ConfigurableListableBeanFactory.class, parent,"Unable to use SearchStrategy.ANCESTORS");beanFactory = (ConfigurableListableBeanFactory) parent;}

如果 Spec 对象的 SearchStrategy 属性是 SearchStrategy.ANCESTORS,则调用 getParentBeanFactory 方法获取其父工厂,并将其转换为 ConfigurableListableBeanFactory 类型。

	MatchResult result = new MatchResult();

新建一个 MatchResult 对象,用于存储匹配结果;

	Set<String> beansIgnoredByType = getNamesOfBeansIgnoredByType(classLoader, beanFactory, considerHierarchy,spec.getIgnoredTypes(), parameterizedContainers);

调用 getNamesOfBeansIgnoredByType 方法,获取被忽略类型的 bean 名称集合 beansIgnoredByType

	for (String type : spec.getTypes()) {Collection<String> typeMatches = getBeanNamesForType(classLoader, considerHierarchy, beanFactory, type,parameterizedContainers);Iterator<String> iterator = typeMatches.iterator();while (iterator.hasNext()) {String match = iterator.next();if (beansIgnoredByType.contains(match) || ScopedProxyUtils.isScopedTarget(match)) {iterator.remove();}}if (typeMatches.isEmpty()) {result.recordUnmatchedType(type);}else {result.recordMatchedType(type, typeMatches);}}

遍历 Spec 对象的 types 属性,它是一个 Set<String> 集合

  • 首先,针对每个类型 type,调用 getBeanNamesForType 方法获取匹配的 bean 名称集合 typeMatches
  • 然后,使用迭代器遍历这个集合,如果集合中的某个元素在被忽略类型的集合中,就将其从迭代器中移除。
  • 最后,如果 typeMatches 集合为空,则记录未匹配的类型;否则,记录匹配的类型。
	for (String annotation : spec.getAnnotations()) {Set<String> annotationMatches = getBeanNamesForAnnotation(classLoader, beanFactory, annotation,considerHierarchy);annotationMatches.removeAll(beansIgnoredByType);if (annotationMatches.isEmpty()) {result.recordUnmatchedAnnotation(annotation);}else {result.recordMatchedAnnotation(annotation, annotationMatches);}}

遍历 Spec 对象的 annotations 属性:

  • 首先,针对每个注解 annotation,调用 getBeanNamesForAnnotation 方法获取匹配的 bean 名称集合 annotationMatches
  • 然后,从 annotationMatches 集合中移除被忽略类型的集合。
  • 最后,如果 annotationMatches 集合为空,则记录未匹配的注解;否则,记录匹配的注解。
	for (String beanName : spec.getNames()) {if (!beansIgnoredByType.contains(beanName) && containsBean(beanFactory, beanName, considerHierarchy)) {result.recordMatchedName(beanName);}else {result.recordUnmatchedName(beanName);}}

遍历 Spec 对象的 names 属性,对于每个 bean 名称,如果它不在被忽略类型的集合中,并且它在 bean 工厂中存在,就记录匹配的名称;否则,记录未匹配的名称。

总结

本篇 Huazie 带大家介绍了自动配置过滤匹配子类 OnBeanCondition ,内容较多,感谢大家的支持;笔者接下来的博文还将详解 OnWebApplicationCondition 的实现,敬请期待!!!

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

美团2024届秋招笔试第一场编程【小美走公路】

题目描述&#xff1a; 有一个环形的公路&#xff0c;上面共有n站&#xff0c;现在给定了顺时针第i站到第i1站之间的距离&#xff08;特殊的&#xff0c;也给出了第n站到第 1 站的距离&#xff09;。小美想沿着公路第x站走到第y站&#xff0c;她想知道最短的距离是多少&#xf…

探索智能应用的基石:多模态大模型赋能文档图像处理

目录 0 写在前面1 文档图像分析新重点2 token荒&#xff1a;电子文档助力大模型3 大模型赋能智能文档分析4 文档图像大模型应用可能性4.1 专有大模型4.2 多模态模型4.3 设计思路 总结 0 写在前面 中国智能产业高峰论坛(CIIS2023)旨在为政企研学各界学者专家提供同台交流的机会…

【微信小程序】scroll-view的基本使用

| scss里面的.item:nth-child(1) index.wxml <view class"scroll"> <scroll-view scroll-x><navigator url"" wx:for"{{6}}" wx:key"index" class"item"><image class"pic" src"/sta…

maven清理本地仓库。删除_remote.repositories文件和删除失败的jar包

1.图预览 .bat文件要和仓库在同一平级目录 REPOSITORY_PATH要改成你自己仓库的地址 2、删除.lastUpdated文件(失败的jar包) 使用.bat文件 注明&#xff1a;REPOSITORY_PATHD:\software\Java\maven\repository 改成你仓库的地址 set REPOSITORY_PATHD:\software\Java\maven\rep…

并发编程——JUC并发工具

文章目录 前言CountDownLatchCountDownLatch应用CountDownLatch核心源码 SemaphoreSemaphore应用Semaphore核心源码 CyclicBarrierCyclicBarrier应用CyclicBarrier核心源码 总结 前言 JUC 是Java并发编程工具类库&#xff0c;提供了一些常用的并发工具&#xff0c;例如锁、信号…

月木学途开发 5.轮播图模块

概述 效果图 数据库设计 轮播图表 DROP TABLE IF EXISTS banner; CREATE TABLE banner (bannerId int(11) NOT NULL AUTO_INCREMENT,bannerUrl longtext,bannerDesc varchar(255) DEFAULT NULL,bannerTypeId int(11) DEFAULT NULL,PRIMARY KEY (bannerId) ) ENGINEInnoDB AU…

一文看懂这些海外社媒平台属性,跨境外贸必看

随着社交媒体平台的普遍使用&#xff0c;在平台上营销品牌形象、投放广告已经成为销售转化的强大动力&#xff0c;我们普遍熟络的都是国内平台&#xff0c;那么对于跨境外贸的小伙伴来说&#xff0c;熟悉海外社媒平台更加重要&#xff01; 当然仅仅用一个社交媒体平台获得流量的…

【办公小神器】:快速批量转换Word、Excel、PPT为PDF脚本!

文章目录 ✨哔哩吧啦✨脚本使用教程✨温馨小提示设置&#x1f4da;资源领取 专栏Python零基础入门篇&#x1f525;Python网络蜘蛛&#x1f525;Python数据分析Django基础入门宝典&#x1f525;小玩意儿&#x1f525;Web前端学习tkinter学习笔记Excel自动化处理 ✨哔哩吧啦 前…

SpringBoot+MyBatisPlus+MySQL不能储存(保存)emoji表情问题解决

1.之前在学习过程中不知道utf8和utf8mb4的区别&#xff0c;也没过多去了解&#xff0c;直到最近设置的数据库编码全是utf8后发现问题所在了&#xff0c;居然不能储存表情包&#xff01;&#xff01;&#xff01;整个人直接傻了&#xff0c;后面知道了utf8是3字节不能储存表情&a…

计算机视觉与深度学习-全连接神经网络-训练过程-模型正则与超参数调优- [北邮鲁鹏]

目录标题 神经网络中的超参数学习率超参数优化方法网格搜索法随机搜索法 超参数搜索策略粗搜索精搜索 超参数的标尺空间 神经网络中的超参数 超参数 网络结构&#xff1a;隐层神经元个数&#xff0c;网络层数&#xff0c;非线性单元选择等优化相关&#xff1a;学习率、dorpou…

Kubernetes(k8s)上搭建一主两从的mysql8集群

Kubernetes上搭建一主两从的mysql8集群 环境准备搭建nfs服务器安装NFS暴露nfs目录开启nfs服务器 安装MySQL集群创建命名空间创建MySQL密码的Secret安装MySQL主节点创建pv和pvc主节点的配置文件部署mysql主节点 安装第一个MySQL Slave节点创建pv和pvc第一个从节点配置文件部署my…

高质量AI数据服务铺路架桥,云测数据引领行业大模型训练新范式

大模型发展风起云涌&#xff0c;使得AI应用又成为了市场热点。但这场创新运动和上一轮AI热潮的背景不同&#xff0c;如今行业不缺技术、也不乏商业模式健康的玩家&#xff0c;最稀缺的资源&#xff0c;已然变成了高质量数据。大模型的模型从何而来&#xff1f;本质上&#xff0…

计算机竞赛 深度学习+opencv+python实现昆虫识别 -图像识别 昆虫识别

文章目录 0 前言1 课题背景2 具体实现3 数据收集和处理3 卷积神经网络2.1卷积层2.2 池化层2.3 激活函数&#xff1a;2.4 全连接层2.5 使用tensorflow中keras模块实现卷积神经网络 4 MobileNetV2网络5 损失函数softmax 交叉熵5.1 softmax函数5.2 交叉熵损失函数 6 优化器SGD7 学…

iOS“超级签名”绕过App Store作弊解决方案

一直以来&#xff0c;iOS端游戏作弊问题都是游戏行业的一大痛点。在当下游戏多端互通的潮流下&#xff0c;游戏作为一个整体&#xff0c;无论哪一端出现安全问题&#xff0c;都会造成更加严重的影响。因此&#xff0c;iOS端游戏安全保护也同样十分重要。 iOS独特的闭源生态&am…

ATFX汇市:美联储宣布维持利率不变,鲍威尔继续发表鹰派言论

ATFX汇市&#xff1a;今日凌晨02:00&#xff0c;美联储公布9月利率决议结果&#xff0c;宣布维持5.25%5.5%的联邦基金利率区间不变。2:002:05&#xff0c;美元指数从最低104.75飙涨至最高105.21&#xff0c;对应EURUSD的汇率从最高1.0727下跌至最低1.0674&#xff0c;跌幅53基点…

基础组件(线程池、内存池、异步请求池、Mysql连接池)

文章目录 1、概述2、线程池2、异步请求池3、内存池 1、概述 池化技术&#xff0c;减少了资源创建次数&#xff0c;提高了程序响应性能&#xff0c;特别是在高并发场景下&#xff0c;当程序7*24小时运行&#xff0c;创建资源可能会出现耗时较长和失败等问题&#xff0c;池化技术…

小谈设计模式(5)—开放封闭原则

小谈设计模式&#xff08;5&#xff09;—开放封闭原则 专栏介绍专栏地址专栏介绍 开放封闭原则核心思想关键词概括扩展封闭 解释抽象和接口多态 代码示例代码解释 优缺点优点可扩展性可维护性可复用性高内聚低耦合 缺点抽象设计的复杂性需要预留扩展点可能引入过度设计 总结 专…

软件工程第一次作业参考答案

题目 名词解释&#xff1a;软件危机、软件、软件工程、软件生命周期、瀑布模型、原型模型、增量模型、喷泉模型、敏捷过程模型。 答案 软件危机&#xff1a;软件危机是指在软件开发过程中所面临的一系列问题和挑战&#xff0c;包括成本超支、进度延误、质量不达标等。 软件…

ubuntu 22.04 服务器网卡无IP地址

ssh连接服务器连接不上&#xff0c;提示如下&#xff1b; 连接显示器&#xff0c;ip addr ls 命令查看IP地址&#xff0c;有网卡但没有IP地址 solution&#xff1a; sudo dhclient enp10s0用于通过 DHCP 协议获取网络配置信息并为名为 enp10s0 的网络接口分配 IP 地址,enp1…

TiDB 7.1.0 LTS 特性解读丨关于资源管控 (Resource Control) 应该知道的 6 件事

TiDB 7.1.0 LTS 在前段时间发布&#xff0c;相信很多同学都已经抢先使用了起来&#xff0c;甚至都已然经过一系列验证推向了生产环境。面对 TiDB 7.1 若干重要特性&#xff0c;新 GA 的资源管控 (Resource Control) 是必须要充分理解、测试的一个重量级特性。对于常年奋斗在一线…