Mr. Cappuccino的第64杯咖啡——Spring循环依赖问题
Spring循环依赖问题
- 什么是循环依赖问题
- 示例
- 项目结构
- 项目代码
- 运行结果
- @Async注解导致的问题
- 使用@Lazy注解解决@Async注解导致的问题
- 开启Aop使用代理对象示例
- 项目结构
- 项目代码
- 运行结果
- Spring是如何解决循环依赖问题的
- 原理
- 源码解读
- 什么情况下Spring无法解决循环依赖问题
什么是循环依赖问题
多个bean之间相互依赖,形成了一个闭环。 比如:A依赖于B、B依赖于C、C依赖于A
通常来说,如果问Spring容器内部如何解决循环依赖问题,一定是指默认的单例Bean中,属性相互引用的场景。也就是说,Spring的循环依赖,是Spring容器注入时出现的问题。
示例
项目结构
项目代码
pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"><modelVersion>4.0.0</modelVersion><groupId>com</groupId><artifactId>spring-circular-dependency</artifactId><version>1.0-SNAPSHOT</version><properties><maven.compiler.source>8</maven.compiler.source><maven.compiler.target>8</maven.compiler.target></properties><dependencies><dependency><groupId>org.springframework</groupId><artifactId>spring-core</artifactId><version>5.2.1.RELEASE</version></dependency><dependency><groupId>org.springframework</groupId><artifactId>spring-beans</artifactId><version>5.2.1.RELEASE</version></dependency><dependency><groupId>org.springframework</groupId><artifactId>spring-context</artifactId><version>5.2.1.RELEASE</version></dependency><dependency><groupId>org.aspectj</groupId><artifactId>aspectjrt</artifactId><version>1.8.9</version></dependency><dependency><groupId>org.apache.geronimo.bundles</groupId><artifactId>aspectjweaver</artifactId><version>1.6.8_2</version></dependency></dependencies></project>
Bean01.java
package com.spring.bean;import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;/*** @author honey* @date 2023-08-23 17:50:53*/
@Component
public class Bean01 {@Autowiredprivate Bean02 bean02;
}
Bean02.java
package com.spring.bean;import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;/*** @author honey* @date 2023-08-23 17:52:55*/
@Component
public class Bean02 {@Autowiredprivate Bean01 bean01;
}
SpringConfig01.java
package com.spring.config;import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;/*** @author honey* @date 2023-08-23 17:59:37*/
@Configuration
@ComponentScan(value = {"com.spring.bean"})
public class SpringConfig01 {
}
SpringTest01.java
package com.spring.test;import com.spring.bean.Bean01;
import com.spring.bean.Bean02;
import com.spring.config.SpringConfig01;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;/*** @author honey* @date 2023-08-23 18:00:24*/
public class SpringTest01 {public static void main(String[] args) {AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(SpringConfig01.class);Bean01 bean01 = applicationContext.getBean("bean01", Bean01.class);Bean02 bean02 = applicationContext.getBean("bean02", Bean02.class);System.out.println(bean01);System.out.println(bean02);}
}
运行结果
Spring默认情况下已经解决了循环依赖问题(单例Bean)
@Async注解导致的问题
在SpringConfig01类上加上@EnableAsync注解
在Bean01类中使用@Async注解修饰的异步方法
Bean01.java
package com.spring.bean;import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Component;/*** @author honey* @date 2023-08-23 17:50:53*/
@Component
public class Bean01 {@Autowiredprivate Bean02 bean02;@Asyncpublic void test() {System.out.println(Thread.currentThread().getName() + "Bean01测试中...");}
}
运行结果
"C:\Program Files\Java\jdk1.8.0_191\bin\java.exe" "-javaagent:C:\Program Files\JetBrains\IntelliJ IDEA 2021.1.1\lib\idea_rt.jar=57456:C:\Program Files\JetBrains\IntelliJ IDEA 2021.1.1\bin" -Dfile.encoding=UTF-8 -classpath "C:\Program Files\Java\jdk1.8.0_191\jre\lib\charsets.jar;C:\Program Files\Java\jdk1.8.0_191\jre\lib\deploy.jar;C:\Program Files\Java\jdk1.8.0_191\jre\lib\ext\access-bridge-64.jar;C:\Program Files\Java\jdk1.8.0_191\jre\lib\ext\cldrdata.jar;C:\Program Files\Java\jdk1.8.0_191\jre\lib\ext\dnsns.jar;C:\Program Files\Java\jdk1.8.0_191\jre\lib\ext\jaccess.jar;C:\Program Files\Java\jdk1.8.0_191\jre\lib\ext\jfxrt.jar;C:\Program Files\Java\jdk1.8.0_191\jre\lib\ext\localedata.jar;C:\Program Files\Java\jdk1.8.0_191\jre\lib\ext\nashorn.jar;C:\Program Files\Java\jdk1.8.0_191\jre\lib\ext\sunec.jar;C:\Program Files\Java\jdk1.8.0_191\jre\lib\ext\sunjce_provider.jar;C:\Program Files\Java\jdk1.8.0_191\jre\lib\ext\sunmscapi.jar;C:\Program Files\Java\jdk1.8.0_191\jre\lib\ext\sunpkcs11.jar;C:\Program Files\Java\jdk1.8.0_191\jre\lib\ext\zipfs.jar;C:\Program Files\Java\jdk1.8.0_191\jre\lib\javaws.jar;C:\Program Files\Java\jdk1.8.0_191\jre\lib\jce.jar;C:\Program Files\Java\jdk1.8.0_191\jre\lib\jfr.jar;C:\Program Files\Java\jdk1.8.0_191\jre\lib\jfxswt.jar;C:\Program Files\Java\jdk1.8.0_191\jre\lib\jsse.jar;C:\Program Files\Java\jdk1.8.0_191\jre\lib\management-agent.jar;C:\Program Files\Java\jdk1.8.0_191\jre\lib\plugin.jar;C:\Program Files\Java\jdk1.8.0_191\jre\lib\resources.jar;C:\Program Files\Java\jdk1.8.0_191\jre\lib\rt.jar;E:\知识点资料(第四年)\Spring源码解读\代码\spring-circular-dependency\target\classes;D:\maven_jar\org\springframework\spring-core\5.2.1.RELEASE\spring-core-5.2.1.RELEASE.jar;D:\maven_jar\org\springframework\spring-jcl\5.2.1.RELEASE\spring-jcl-5.2.1.RELEASE.jar;D:\maven_jar\org\springframework\spring-beans\5.2.1.RELEASE\spring-beans-5.2.1.RELEASE.jar;D:\maven_jar\org\springframework\spring-context\5.2.1.RELEASE\spring-context-5.2.1.RELEASE.jar;D:\maven_jar\org\springframework\spring-aop\5.2.1.RELEASE\spring-aop-5.2.1.RELEASE.jar;D:\maven_jar\org\springframework\spring-expression\5.2.1.RELEASE\spring-expression-5.2.1.RELEASE.jar;D:\maven_jar\org\aspectj\aspectjrt\1.8.9\aspectjrt-1.8.9.jar;D:\maven_jar\org\apache\geronimo\bundles\aspectjweaver\1.6.8_2\aspectjweaver-1.6.8_2.jar" com.spring.test.SpringTest01
八月 23, 2023 7:07:05 下午 org.springframework.context.support.AbstractApplicationContext refresh
警告: Exception encountered during context initialization - cancelling refresh attempt: org.springframework.beans.factory.BeanCurrentlyInCreationException: Error creating bean with name 'bean01': Bean with name 'bean01' has been injected into other beans [bean02] in its raw version as part of a circular reference, but has eventually been wrapped. This means that said other beans do not use the final version of the bean. This is often the result of over-eager type matching - consider using 'getBeanNamesOfType' with the 'allowEagerInit' flag turned off, for example.
Exception in thread "main" org.springframework.beans.factory.BeanCurrentlyInCreationException: Error creating bean with name 'bean01': Bean with name 'bean01' has been injected into other beans [bean02] in its raw version as part of a circular reference, but has eventually been wrapped. This means that said other beans do not use the final version of the bean. This is often the result of over-eager type matching - consider using 'getBeanNamesOfType' with the 'allowEagerInit' flag turned off, for example.at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:624)at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:517)at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:323)at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:222)at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:321)at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:202)at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:879)at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:878)at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:550)at org.springframework.context.annotation.AnnotationConfigApplicationContext.<init>(AnnotationConfigApplicationContext.java:89)at com.spring.test.SpringTest01.main(SpringTest01.java:15)Process finished with exit code 1
Spring在扫描bean发现某个类方法被@Async修饰时,会通过后置处理器AsyncAnnotationBeanPostProcessor生成代理对象,而该后置处理器的顺序比处理AOP的后置处理器还靠后,因此会导致Spring处理不了循环依赖。
使用@Lazy注解解决@Async注解导致的问题
在Bean01类中循环依赖的属性上使用@Lazy注解
运行结果
开启Aop使用代理对象示例
项目结构
项目代码
AspectAop.java
package com.spring.aop;import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Component;/*** @author honey* @date 2023-08-23 18:26:33*/
@Component
@Aspect
public class AspectAop {@Pointcut("execution (* com.spring.bean.*.*(..))")public void pointcut() {}@Around(value = "pointcut()")public Object doAround(ProceedingJoinPoint point) throws Throwable {System.out.println("doAround advice start");Object result = point.proceed();System.out.println("doAround advice end");return result;}
}
需要在Bean01和Bean02中加上一个普通方法,如:
package com.spring.bean;import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;/*** @author honey* @date 2023-08-23 17:52:55*/
@Component
public class Bean02 {@Autowiredprivate Bean01 bean01;public void add() {}
}
SpringConfig01.java
package com.spring.config;import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.EnableAspectJAutoProxy;/*** @author honey* @date 2023-08-23 17:59:37*/
@Configuration
@ComponentScan(value = {"com.spring.bean", "com.spring.aop"})
@EnableAspectJAutoProxy
public class SpringConfig01 {
}
运行结果
Spring是如何解决循环依赖问题的
Spring底层通过三级缓存解决了循环依赖问题。
一级缓存:singletonObjects,也叫作单例池,存放已经经历了完整生命周期的Bean对象;
/** Cache of singleton objects: bean name to bean instance. */
private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256);
二级缓存:earlySingletonObjects,存放早期暴露出来的Bean对象,Bean的生命周期未结束(属性还未填充完整);
/** Cache of early singleton objects: bean name to bean instance. */
private final Map<String, Object> earlySingletonObjects = new HashMap<>(16);
三级缓存:singletonFactories,存放可以生成Bean的工厂;
/** Cache of singleton factories: bean name to ObjectFactory. */
private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<>(16);
原理
假设有两个对象分别是A和B,其中A依赖于B,B依赖于A
- 在创建A对象时需要B对象,于是将A对象存入三级缓存,再去创建B对象;
- 在创建B对象时发现需要A对象,于是先查一级缓存,没有,再查二级缓存,还是没有,再查三级缓存,找到了A对象,然后把三级缓存里面的A对象存入二级缓存,并删除三级缓存里面的A对象;
- B对象创建完成,将B对象存入一级缓存(此时B对象依赖的A对象依然是创建中状态),获取到B对象后回来接着创建A对象,直到创建完成,并将A对象存入一级缓存中(如果其它对象依赖于A对象和B对象,可以直接从一级缓存里面获取);
源码解读
在创建A对象时,A对象完成实例化后,会将A对象封装成ObjectFactory存入三级缓存。
AbstractBeanFactory.java
AbstractAutowireCapableBeanFactory.java
ObjectFactory.java
如果该对象是单例对象且开启了循环依赖且该对象正在创建中,则会将该对象封装成ObjectFactory对象存入三级缓存。其中ObjectFactory是一个函数接口,在调用getObject()方法时,才会真正去执行lambda语句调用getEarlyBeanReference()方法。
// Eagerly cache singletons to be able to resolve circular references
// even when triggered by lifecycle interfaces like BeanFactoryAware.
boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences &&isSingletonCurrentlyInCreation(beanName));
if (earlySingletonExposure) {if (logger.isTraceEnabled()) {logger.trace("Eagerly caching bean '" + beanName +"' to allow for resolving potential circular references");}addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
}
DefaultSingletonBeanRegistry.java
在为A对象设置属性时,发现A对象依赖于B对象,则会去尝试获取B对象,由于此时B对象还未被创建,所以B对象也会走和A对象一样的创建逻辑,不同的是在为B对象设置属性时,发现B对象依赖于A对象,可以从三级缓存中获取得到A对象。
AbstractBeanFactory.java
DefaultSingletonBeanRegistry.java
此时存入二级缓存的是不完整对象,调用singletonFactory.getObject()方法实际上是在调用getEarlyBeanReference(beanName, mbd, bean)方法。
如果是正常情况下,返回原始对象
InstantiationAwareBeanPostProcessorAdapter.java
如果是开启了Aop的情况下,返回Aop代理对象
AbstractAutoProxyCreator.java
将获取到的A对象设置为B对象的属性并执行完B对象的完整生命周期后,将B对象存入一级缓存中并从二级缓存、三级缓存中移除。此处也使用了ObjectFactory这个函数接口。
AbstractBeanFactory.java
DefaultSingletonBeanRegistry.java
获取得到B对象后,接着执行A对象的生命周期,执行完成后和B对象一样存入一级缓存中。
什么情况下Spring无法解决循环依赖问题
- 构造器注入的循环依赖问题;
- 非单例对象的循环依赖问题;
相关文章:

Mr. Cappuccino的第64杯咖啡——Spring循环依赖问题
Spring循环依赖问题 什么是循环依赖问题示例项目结构项目代码运行结果 Async注解导致的问题使用Lazy注解解决Async注解导致的问题开启Aop使用代理对象示例项目结构项目代码运行结果 Spring是如何解决循环依赖问题的原理源码解读 什么情况下Spring无法解决循环依赖问题 什么是循…...
Adapting Language Models to Compress Contexts
本文是LLM系列文章,针对《Adapting Language Models to Compress Contexts》的翻译。 使语言模型适应上下文压缩 摘要1 引言2 相关工作3 方法4 实验5 上下文学习6 压缩检索语料库实现高效推理7 结论不足 摘要 1 引言 2 相关工作 3 方法 4 实验 5 上下文学习 …...

Kubernetes(K8S)使用PV和PVC做存储安装mysql
Kubernetes使用PV和PVC做存储安装mysql 环境准备什么是PV和PVC环境准备配置nfs安装nfs配置nfs服务端 创建命名空间配置pv和pvcpv的yaml文件pvc的yaml文件 部署mysql创建mysql的root密码的secret创建mysql部署的yaml部署mysql链接mysql外部链接内部链接 环境准备 首先你需要一个…...
Ansible Playbook 常用变量
以下是 Ansible Playbook 常用变量 ansible_connection: 指定连接类型(如 ssh、winrm) ansible_user: 指定远程用户 ansible_ssh_pass: 指定远程用户密码 ansible_become: 指定是否切换为超级用户 ansible_become_user: 指定切换到的用户 ansible_b…...

0103水平分片-jdbc-shardingsphere-中间件
文章目录 1 准备服务器1.1 创建server-order0容器1.2 创建server-order1容器 2、基本水平分片2.1、基本配置2.2、数据源配置2.3、标椎分片表配置2.4、行表达式2.5、分片算法配置2.6、分布式序列算法 3、多表关联3.1、创建关联表3.2、创建实体类3.3、创建Mapper3.4、配置关联表3…...

Vue2.0+webpack 引入字体文件(eot,ttf,woff)
webpack.base.config.js 需要配置 {test:/\/(woff2?|eot|ttf|otf)(\?.*)?$/,loader: url-loader,options: {limit: 10000,name: utils.assetsPath(fonts/[name].[hash:7].[ext])}} 如果 Vue2.0webpack3.6引入字体文件(eot,ttf,woff&…...
WPF入门到精通:3.MVVM简单应用及全局异常处理
MVVM简介 在WPF应用程序开发中,MVVM(Model-View-ViewModel)是一种非常流行的架构模式。它为应用程序的设计提供了良好的分层结构和可扩展性。 结构分为下列三部分 Model:定义了应用程序的数据模型 就是系统中的对象,…...

Springboot+mybatis-plus+dynamic-datasource+Druid 多数据源 分布式事务
Springbootmybatis-plusdynamic-datasourceDruid 多数据源事务,分布式事务 文章目录 Springbootmybatis-plusdynamic-datasourceDruid 多数据源事务,分布式事务0.前言1. 基础介绍ConnectionFactoryAbstractRoutingDataSource 动态路由数据源的抽象类 Dyn…...

673. 最长递增子序列的个数
673. 最长递增子序列的个数 原题链接:完成情况:解题思路:方法一:动态规划方法二:贪心 前缀和 二分查找 参考代码:__673最长递增子序列的个数__动态规划__673最长递增子序列的个数__贪心_前缀和_二分查找…...

Android12之ABuffer数据处理(三十四)
简介: CSDN博客专家,专注Android/Linux系统,分享多mic语音方案、音视频、编解码等技术,与大家一起成长! 优质专栏:Audio工程师进阶系列【原创干货持续更新中……】🚀 人生格言: 人生从来没有捷径,只有行动才是治疗恐惧和懒惰的唯一良药. 更多原创,欢迎关注:Android…...

whisper 语音识别项目部署
1.安装anaconda软件 在如下网盘免费获取软件: 链接:https://pan.baidu.com/s/1zOZCQOeiDhx6ebHh5zNasA 提取码:hfnd 2.使用conda命令创建python3.8环境 conda create -n whisper python3.83.进入whisper虚拟环境 conda activate whisper4.…...

实例044 在关闭窗口前加入确认对话框
实例说明 用户对程序进行操作时,难免会有错误操作的情况,例如不小心关闭程序,如果尚有许多资料没有保存,那么损失将非常严重,所以最好使程序具有灵活的交互性。人机交互过程一般都是通过对话框来实现的,对话…...

子查询和事务隔离以及用户管理
一、子查询 子查询是另一个语句中的select语句嵌套在另一个select中。注意子查询语法上必须使用()包起来。 嵌套的那个语句返回的结果有可能是: 一个字段,一行记录,一个列或一个表。嵌套的位置 where / having语句里面作为条件使用在from语…...
uniapp 滚动到指定元素的位置(锚点)
需求:在页面中,不管位于何处,点击按钮页面滚动到对应的标题位置。 最简单有效的方式(直接复制改数据就行) 使用 scroll-view 标签的属性:scroll-top(距离值 num) 或 scroll-into-view(子元素的id,不能以…...
Spring AOP 的 afterReturing 返回值是否能修改问题
文章目录 结论举例子原因外传 结论 最近要搞脱敏信息,所以,想了几种方案,最后使用全局的接口拦截,但是,又不能用注解的方式,毕竟是几年的老产品,有很多限制。 中间尝试过使用Spring AOP 的 aft…...

MyBatis分页插件PageHelper的使用及特殊字符的处理
目录 一、PageHelper简介 1.什么是分页 2.PageHelper是什么 3.使用PageHelper的优点 二、PageHelper插件的使用 原生limit查询 1. 导入pom依赖 2. Mybatis.cfg.xml 配置拦截器 3. 使用PageHelper进行分页 三、特殊字符的处理 1.SQL注入: 2.XML转义&#…...

[语音识别] 基于Python构建简易的音频录制与语音识别应用
语音识别技术的快速发展为实现更多智能化应用提供了无限可能。本文旨在介绍一个基于Python实现的简易音频录制与语音识别应用。文章简要介绍相关技术的应用,重点放在音频录制方面,而语音识别则关注于调用相关的语音识别库。本文将首先概述一些音频基础概…...

Matlab彩色图像转索引图像
索引图像 索引图像是一种把像素值直接作为RGB调色板下标的图像。索引图像包括一个数据矩阵X,一个调色板矩阵map,也称为颜色映像矩阵。其中,数据矩阵X可以是8位无符号整型、16位无符号整型或双精度类型。调色板矩阵map是一个m3的数据阵列&…...

测试框架pytest教程(11)-pytestAPI
常量 pytest.__version__ #输出pytest版本 pytest.version_tuple #输出版本的元组形式 功能 pytest.approx pytest.approx 是一个用于进行数值近似比较的 pytest 断言工具。 在测试中,有时候需要对浮点数或其他具有小数部分的数值进行比较。然而,由于…...

XML Group端口详解
在XML数据映射过程中,经常需要对数据进行分组聚合操作。例如,当处理包含多个物料明细的XML文件时,可能需要将相同物料号的明细归为一组,或对相同物料号的数量进行求和计算。传统实现方式通常需要编写脚本代码,增加了开…...
蓝桥杯 2024 15届国赛 A组 儿童节快乐
P10576 [蓝桥杯 2024 国 A] 儿童节快乐 题目描述 五彩斑斓的气球在蓝天下悠然飘荡,轻快的音乐在耳边持续回荡,小朋友们手牵着手一同畅快欢笑。在这样一片安乐祥和的氛围下,六一来了。 今天是六一儿童节,小蓝老师为了让大家在节…...
Python如何给视频添加音频和字幕
在Python中,给视频添加音频和字幕可以使用电影文件处理库MoviePy和字幕处理库Subtitles。下面将详细介绍如何使用这些库来实现视频的音频和字幕添加,包括必要的代码示例和详细解释。 环境准备 在开始之前,需要安装以下Python库:…...
css3笔记 (1) 自用
outline: none 用于移除元素获得焦点时默认的轮廓线 broder:0 用于移除边框 font-size:0 用于设置字体不显示 list-style: none 消除<li> 标签默认样式 margin: xx auto 版心居中 width:100% 通栏 vertical-align 作用于行内元素 / 表格单元格ÿ…...

使用 SymPy 进行向量和矩阵的高级操作
在科学计算和工程领域,向量和矩阵操作是解决问题的核心技能之一。Python 的 SymPy 库提供了强大的符号计算功能,能够高效地处理向量和矩阵的各种操作。本文将深入探讨如何使用 SymPy 进行向量和矩阵的创建、合并以及维度拓展等操作,并通过具体…...
基于Java Swing的电子通讯录设计与实现:附系统托盘功能代码详解
JAVASQL电子通讯录带系统托盘 一、系统概述 本电子通讯录系统采用Java Swing开发桌面应用,结合SQLite数据库实现联系人管理功能,并集成系统托盘功能提升用户体验。系统支持联系人的增删改查、分组管理、搜索过滤等功能,同时可以最小化到系统…...

保姆级教程:在无网络无显卡的Windows电脑的vscode本地部署deepseek
文章目录 1 前言2 部署流程2.1 准备工作2.2 Ollama2.2.1 使用有网络的电脑下载Ollama2.2.2 安装Ollama(有网络的电脑)2.2.3 安装Ollama(无网络的电脑)2.2.4 安装验证2.2.5 修改大模型安装位置2.2.6 下载Deepseek模型 2.3 将deepse…...

MFC 抛体运动模拟:常见问题解决与界面美化
在 MFC 中开发抛体运动模拟程序时,我们常遇到 轨迹残留、无效刷新、视觉单调、物理逻辑瑕疵 等问题。本文将针对这些痛点,详细解析原因并提供解决方案,同时兼顾界面美化,让模拟效果更专业、更高效。 问题一:历史轨迹与小球残影残留 现象 小球运动后,历史位置的 “残影”…...
C++课设:简易日历程序(支持传统节假日 + 二十四节气 + 个人纪念日管理)
名人说:路漫漫其修远兮,吾将上下而求索。—— 屈原《离骚》 创作者:Code_流苏(CSDN)(一个喜欢古诗词和编程的Coder😊) 专栏介绍:《编程项目实战》 目录 一、为什么要开发一个日历程序?1. 深入理解时间算法2. 练习面向对象设计3. 学习数据结构应用二、核心算法深度解析…...
Go语言多线程问题
打印零与奇偶数(leetcode 1116) 方法1:使用互斥锁和条件变量 package mainimport ("fmt""sync" )type ZeroEvenOdd struct {n intzeroMutex sync.MutexevenMutex sync.MutexoddMutex sync.Mutexcurrent int…...