Spring之bean的生命周期
目录
1.Bean的初始化过程
1.1代码详解
1.2思考
2.Bean的单例与多例选择
2.1论证单例与多例优缺点
2.2论证初始化时间点
2.3个例演示
Spring Bean的生命周期:
一、通过XML、Java annotation(注解)以及Java Configuration(配置类),等方式加载Spring Bean
二、BeanDefinitionReader:解析Bean的定义。在Spring容器启动过程中,会将Bean解析成Spring内部的BeanDefinition结构;理解为:将spring.xml中的<bean>标签转换成BeanDefinition结构(有点类似于XML解析)
三、BeanDefinition:包含了很多属性和方法。例如:id、class(类名)、scope、ref(依赖的bean)等等。其实就是将bean(例如<bean>)的定义信息
存储到这个对应BeanDefinition相应的属性中
四、BeanFactoryPostProcessor:是Spring容器功能的扩展接口。
注意:
1)BeanFactoryPostProcessor在spring容器加载完BeanDefinition之后,
在bean实例化之前执行的
2)对bean元数据(BeanDefinition)进行加工处理,也就是BeanDefinition
属性填充、修改等操作
五、BeanFactory:bean工厂。它按照我们的要求生产我们需要的各种各样的bean。
六、Aware感知接口:在实际开发中,经常需要用到Spring容器本身的功能资源
例如:BeanNameAware、ApplicationContextAware等等
BeanDefinition 实现了 BeanNameAware、ApplicationContextAware
七、BeanPostProcessor:后置处理器。在Bean对象实例化和引入注入完毕后,
在显示调用初始化方法的前后添加自定义的逻辑。(类似于AOP的绕环通知)
前提条件:如果检测到Bean对象实现了BeanPostProcessor后置处理器才会执行
Before和After方法
BeanPostProcessor
1)Before
2)调用初始化Bean(InitializingBean和init-method,Bean的初始化才算完成)
3)After
完成了Bean的创建工作
八、destory:销毁
1.Bean的初始化过程
1.xml/annotation/configuation/配置JavaBean
2.BeanDefinitionReader解析配置的JavaBean得到Beandefinition,最终得到List<BeanDefinition>集合
3.触发BeanFactoryPostProcessor,在JavaBean初始化之前执行
4.Spring中的BeanFactory,会通过List<BeanDefinition>集合遍历初始化所有的JavaBean对象
5.如果自己的JavaBean需要调动Spring上下文中的资源(方法或属性),那么需要实现*Aware感知接口
6.如果自己的JavaBean已经初始化好了,还需扩展功能,那么需要借助BeanPostProcessor后置处理器来实现
具体图解与流程图如下:
1.1代码详解
BeanFactoryPostProcessor是Spring容器功能的扩展接口,怎么理解?比如假设我们现在有一个内部类Person,其原本有三个属性。BeanFactoryPostProcessor的作用就是可以在初始化对象之前可以做一个补充,它内部类原本只有三个属性,我们可以给它加一个关联属性User进去,并对新增的关联属性User对象做出相对应的处理,具体代码详解如下:
package com.kissship.beanlife;/*** @author Kissship* @site www.Kissship.com* @company xxx公司* @create 2023-08-18-14:17*/
public class Demo1 {public static void main(String[] args) {
// BeanDefinition}
}class User{
//无值
}
class Person{private int pid;private String name;private String sex;private User user;//扩展新增的关联属性(无值)public int getPid() {return pid;}public void setPid(int pid) {this.pid = pid;}public String getName() {return name;}public void setName(String name) {this.name = name;}public String getSex() {return sex;}public void setSex(String sex) {this.sex = sex;}public Person() {}//在初始化对象之前可以做一个补充,比如上面原本只有三个属性,我们也可以给它加一个关联属性Userpublic Person(int pid, String name, String sex) {this.init();//扩展的内容this.pid = pid;this.name = name;this.sex = sex;}//这里可以针对我们新增的关联属性User对象作出处理public void init() {}
}
解析配置得到List集合与遍历初始化Bean对象,具体代码详解如下:
import org.springframework.beans.factory.config.BeanDefinition;import java.util.ArrayList;
import java.util.List;/*** @author Kissship* @site www.Kissship.com* @company xxx公司* @create 2023-08-18-14:17*/
public class Demo1 {//初始化Beanpublic static void main(String[] args) throws ClassNotFoundException {
// 2.BeanDefinitionReader解析配置的JavaBean得到Beandefinition,最终得到List<BeanDefinition>集合List<BeanDefinition> beans = new ArrayList<>();//BeanDefinitionReader把spring-context.xml中所有的bean标签都解析成了List集合for (BeanDefinition bean : beans) {
// 4.Spring中的BeanFactory,会通过List<BeanDefinition>集合遍历初始化所有的JavaBean对象String beanClassName = bean.getBeanClassName();//得到的就是spring-context.xml中bean标签中class里的值Class.forName(beanClassName);//将配置的所有JavaBean进行反射实例化}}
}
如果自己的JavaBean需要调动Spring上下文中的资源(方法或属性),那么需要实现*Aware感知接口(比如BeanDefinition实现了BeanNameAware、ApplicationContextAware接口)具体详解如下:
Aware接口:
实现Aware接口:
1.2思考
那么现在有个问题,当我们的Spring容器初始化Bean完成之后,我们可能还需要加工一下,即进行再初始化。因为并不是每一个类都是我们自己写的。也许我们需要用别人的类内容,然后在此基础上再进行拓展。那么在此时我们能改动别人写的类里面的源码吗?不能。因为这样有可能影响到其他的功能,这时候我们的解决办法就是自己写一个类去继承别人的类然后进行再一波初始化,我们这里以BaseDao为例:
BaseDao为父类,MyBaseDao为子类:
我们需要在继承BaseDao方法后,在子类中进行初始化方法的重写(即再一次初始化),具体如下:
package com.kissship.beanlife;/*** @author Kissship* @site www.Kissship.com* @company xxx公司* @create 2023-08-18-15:58*/
//继承原本的BaseDao
public class MyBaseDao extends BaseDao{public MyBaseDao(){//重写初始化方法super();System.out.println("初始化...");}
}
那么在此时如果我们在初始化之后不满意,在初始化之后想修改Bean的内容,可以利用BeanPostProcessor后置处理器来完成。这时候可以在Bean对象实例化和引入注入完毕后,在显示调用初始化方法的前后添加自定义逻辑。(类似于AOP的环绕通知)环绕通知不了解的可以通过下面链接进行跳转至对应博客界面,如下:
Kissship的博客Spring之AOP篇https://blog.csdn.net/weixin_74263417/article/details/132340241?spm=1001.2014.3001.5501那么到这里我们就完成了Bean的创建工作。
2.Bean的单例与多例选择
1.在Spring中JavaBean默认是单例的,但是可以配置多例。
2.单例的优点:节约内存。弊端:有变量污染。
多例的优点:无变量污染。弊端:极其消耗内存。
3.单例:JavaBean是跟着spring上下文初始化的;容器生对象生,容器死对象死(此处对象指JavaBean)。
多例:JavaBean在使用时才会创建,销毁跟着jvm走。
4.第三点并不绝对正确,个别情况会有所个例。
2.1论证单例与多例优缺点
准备工作:
ParamAction:
package com.kissship.beanlife;import java.util.List;public class ParamAction {private int age;private String name;private List<String> hobby;private int num = 1;// private UserBiz userBiz = new UserBizImpl1();public ParamAction() {super();}public ParamAction(int age, String name, List<String> hobby) {super();this.age = age;this.name = name;this.hobby = hobby;}public void execute() {// userBiz.upload();// userBiz = new UserBizImpl2();System.out.println("this.num=" + this.num++);System.out.println(this.name);System.out.println(this.age);System.out.println(this.hobby);}
}
InstanceFactory(Bean工厂):
package com.kissship.beanlife;public class InstanceFactory {public void init() {System.out.println("初始化方法");}public void destroy() {System.out.println("销毁方法");}public void service() {System.out.println("业务方法");}
}
spring-context.xml进行配置(生命周期部分):
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"default-autowire="byType"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"><!-- ioc的javabean-->
<!-- 凡是在Spring配置文件spring-context.xml中配置,那么该类javabean就交给了Spring容器管理--><bean class="com.kissship.ioc.web.UserAction" id="userAction"><property name="userService" ref="userService"></property>
<!-- <constructor-arg name="uname" value="扎克" ></constructor-arg>-->
<!-- <constructor-arg name="age" value="18" ></constructor-arg>-->
<!-- <constructor-arg name="hobby">-->
<!-- <list>-->
<!-- <value>唱,跳</value>-->
<!-- <value>Rap</value>-->
<!-- <value>篮球</value>-->
<!-- </list>-->
<!-- </constructor-arg>--></bean><bean class="com.kissship.ioc.web.GoodsAction" id="goodsAction"><property name="userService" ref="userServiceImpl1"></property>
<!-- <property name="gname" value="小文"></property>-->
<!-- <property name="age" value="19"></property>-->
<!-- <property name="peoples">-->
<!-- <list>-->
<!-- <value>印度飞饼</value>-->
<!-- <value>意大利炮</value>-->
<!-- <value>北京烤鸭</value>-->
<!-- <value>墨西哥卷</value>-->
<!-- </list>-->
<!-- </property>--></bean><bean class="com.kissship.ioc.service.impl.UserServiceImpl2" id="userService"></bean><bean class="com.kissship.ioc.service.impl.UserServiceImpl1" id="userServiceImpl1"></bean><!-- aop相关的Javabean--><!--目标对象--><bean class="com.kissship.aop.biz.impl.BookBizImpl" id="bookBiz"></bean><!--通知--><bean class="com.kissship.aop.advice.MyMethodBeforeAdvice" id="methodBeforeAdvice"></bean><bean class="com.kissship.aop.advice.MyAfterReturningAdvice" id="myAfterReturningAdvice"></bean><bean class="com.kissship.aop.advice.MyMethodInterceptor" id="myMethodInterceptor"></bean><bean class="com.kissship.aop.advice.MyThrowsAdvice" id="myThrowsAdvice"></bean><bean class="org.springframework.aop.support.RegexpMethodPointcutAdvisor" id="regexpMethodPointcutAdvisor"><property name="advice" ref="myAfterReturningAdvice"></property><property name="pattern" value=".*buy"></property></bean><!--代理--><bean class="org.springframework.aop.framework.ProxyFactoryBean" id="bookProxy">
<!-- 配置目标对象--><property name="target" ref="bookBiz"></property>
<!-- 配置代理接口,目标对象的接口--><property name="proxyInterfaces"><list><value>com.kissship.aop.biz.IBookBiz</value></list></property>
<!-- 配置通知--><property name="interceptorNames"><list><value>methodBeforeAdvice</value>
<!-- <value>myAfterReturningAdvice</value>--><value>regexpMethodPointcutAdvisor</value><value>myMethodInterceptor</value><value>myThrowsAdvice</value></list></property></bean><!-- Spring的生命周期--><bean class="com.kissship.beanlife.ParamAction" id="paramAction"><constructor-arg name="name" value="刘三金"></constructor-arg><constructor-arg name="age" value="19"></constructor-arg><constructor-arg name="hobby"><list><value>来自星星的哥</value><value>天空一声巨响</value><value>劳资闪亮登场</value></list></constructor-arg></bean><bean class="com.kissship.beanlife.InstanceFactory" id="instanceFactory"scope="prototype" init-method="init" destroy-method="destroy"></bean></beans>
测试类Demo2:
package com.kissship.beanlife;import org.junit.Test;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.xml.XmlBeanFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.Resource;/** spring bean的生命週期* spring bean的單例多例*/
public class Demo2 {// 体现单例与多例的区别@Testpublic void test1() {ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("/spring-context.xml");
// ApplicationContext applicationContext = new ClassPathXmlApplicationContext("/spring-context.xml");ParamAction p1 = (ParamAction) applicationContext.getBean("paramAction");ParamAction p2 = (ParamAction) applicationContext.getBean("paramAction");// System.out.println(p1==p2);p1.execute();p2.execute();// 单例时,容器销毁instanceFactory对象也销毁;多例时,容器销毁对象不一定销毁;applicationContext.close();}// 体现单例与多例的初始化的时间点 instanceFactory@Testpublic void test2() {ApplicationContext applicationContext = new ClassPathXmlApplicationContext("/spring-context.xml");}// BeanFactory会初始化bean对象,但会根据不同的实现子类采取不同的初始化方式// 默认情况下bean的初始化,单例模式立马会执行,但是此时XmlBeanFactory作为子类,单例模式下容器创建,bean依赖没有初始化,只有要获取使用bean对象才进行初始化@Testpublic void test3() {// ClassPathXmlApplicationContext applicationContext = new// ClassPathXmlApplicationContext("/spring-context.xml");Resource resource = new ClassPathResource("/spring-context.xml");BeanFactory beanFactory = new XmlBeanFactory(resource);
// InstanceFactory i1 = (InstanceFactory) beanFactory.getBean("instanceFactory");}}
执行Demo2结果如下:
那么我们换上多例后会是什么结果?
具体实操,在spring-context.xml中ParamAtion的Bean配置的class属性里加上scope属性并赋值多例(原型模式) ,如下:
修改后我们继续执行Demo2测试类看看效果:
2.2论证初始化时间点
Demo2里已经写了体现单例与多例的初始化时间点的方法,所以我们只需要在spring-context.xml中给它定一个多例的属性值然后测试看效果即可,xml代码如下:
<bean class="com.kissship.beanlife.InstanceFactory" id="instanceFactory"scope="prototype" init-method="init" destroy-method="destroy"></bean>
然后我们运行Demo2看看效果,如下:
紧接着我们换成单例,如下:
<bean class="com.kissship.beanlife.InstanceFactory" id="instanceFactory"scope="singleton" init-method="init" destroy-method="destroy"></bean>
执行方法看效果,如下:
那么现在问题又来了,虽然验证了单例与多例的初始化时间点,但是看不出到底是不是使用Spring创建的,那么现在我们上代码验证看看结果。刚刚我们在演示时多例并没有执行初始化方法,现在我们把xml文件里的单例改成多例,然后再Demo2测试类中加上以下代码:
然后再运行一次看效果:
2.3个例演示
BeanFactory会初始化bean对象,但会根据不同的实现子类采取不同的初始化方式。
默认情况下bean的初始化,单例模式会立马执行,但是此时XmlBeanFactory作为子类,单例模式下容器创建,bean依赖没有初始化·,只有要获取使用bean对象才进行初始化。
验证:
1.先把xml多例模式改为单例,然后运行Test2方法,再运行Test3方法,比较结果。
2.然后把Test3注释的代码部分放开再执行比较结果。
运行Test2的结果(先注释论证是否为Sprring创建新增的代码再运行):
运行Test3的结果:
然后取消注释,如下:
再执行一次Test3,效果如下:
最后Spring之bean的生命周期就到这里,祝大家在敲代码的路上一路通畅!
相关文章:

Spring之bean的生命周期
目录 1.Bean的初始化过程 1.1代码详解 1.2思考 2.Bean的单例与多例选择 2.1论证单例与多例优缺点 2.2论证初始化时间点 2.3个例演示 Spring Bean的生命周期: 一、通过XML、Java annotation(注解)以及Java Configuration(配置类),等方式…...

策略梯度方法
策略梯度方法 数学背景 给定一个标量函数 J ( θ ) J\left(\theta\right) J(θ),利用梯度上升法,使其最大化,此时的 π θ \pi_\theta πθ就是最优策略。 θ t 1 θ t α ∇ θ J ( θ t ) \theta_{t1}\theta_t\alpha \nabla_\theta…...

博客系统之单元测试
对博客系统进行单元测试 1、测试查找已存在的用户 测试名称 selectByUsernameTest01 测试源码 //查找用户,存在 Test public void selectByUsernameTest01 () { UserDao userDao new UserDao(); String ret1 userDao.selectByUsername("张三").toStr…...

【ARM v8】如何在ARM上实现x86的rdtsc()函数
博主未授权任何人或组织机构转载博主任何原创文章,感谢各位对原创的支持! 博主链接 本人就职于国际知名终端厂商,负责modem芯片研发。 在5G早期负责终端数据业务层、核心网相关的开发工作,目前牵头6G算力网络技术标准研究。 博客…...
redis--事务
redis事务 在Redis中,事务是一组原子性操作的集合,它们被一起执行,要么全部执行成功,要么全部回滚。虽然Redis的事务并不遵循传统数据库的ACID特性,但它仍然提供了一种将多个命令打包成一组执行的机制,适用…...
111. 二叉树的最小深度
111. 二叉树的最小深度 给定一个二叉树,找出其最小深度。 最小深度是从根节点到最近叶子节点的最短路径上的节点数量。 说明:叶子节点是指没有子节点的节点。 /*** Definition for a binary tree node.* struct TreeNode {* int val;* TreeN…...
SpringMVC归纳与总结
前言 Spring的核心是IOC,一种依赖反转的解耦思想。MVC是一种处理Web请求的架构模式,当两者的作用结合,就形成了SpringMVC。 组成及运行原理 1. 两次映射 2. 为什么用适配器模式 过滤器与拦截器 1. 范围 静态资源与动态资源2. 生命周期…...
Python学习笔记_进阶篇(三)_django知识(二)
本章内容 Django model Model 基础配置 django默认支持sqlite,mysql, oracle,postgresql数据库。 <1> sqlite django默认使用sqlite的数据库,默认自带sqlite的数据库驱动 引擎名称:django.db.backends.sqlite3 <2>mysql …...
RISC-V 整型通用寄存器介绍
简介 RISC-V64位/32位提供了32个整型通用寄存器,编号是x0~x31,这些整型通用寄存器的宽度与架构位数一致。 浮点数寄存器与整形寄存器一样也提供了32个:f0~f31,位数与架构位数一致。 通用寄存器介绍 零寄存器 x0/zero x0寄存…...
学习Vue:【性能优化】异步组件和懒加载
在Vue.js应用开发中,性能优化是一个至关重要的主题,而异步组件和懒加载是提升性能的有效方法之一。本文将介绍什么是异步组件和懒加载,以及如何在Vue.js中应用这些技术来提升应用性能。 异步组件和懒加载 异步组件 异步组件是指在需要的时候…...

pdf格式文件下载不预览,云存储的跨域解决
需求背景 后端接口中返回的是pdf文件路径比如: pdf文件路径 (https://wangzhendongsky.oss-cn-beijing.aliyuncs.com/wzd-test.pdf) 前端适配是这样的 <ahref"https://wangzhendongsky.oss-cn-beijing.aliyuncs.com/wzd-test.pdf&…...
httplib + nlohmann::json上传数据时中文乱码解决
1、nlohmann::json 1.1 编码格式使用UTF-8 参考 nlohmann::json 中文乱码解决方案 (1)将数据先转为UTF-8格式 2、httplib 2.1 上传数据前 (1)调用httplib::Response对象的set_header()方法来设置编码格式 httplib::Response res…...
JavaScript中的设计模式之一--单例模式和模块
虽然有一种疯狂天才的感觉可能很诱人,但重新发明轮子通常不是设计软件的最佳方法。很有可能有人已经遇到了和你一样的问题,并以一种聪明的方式解决了它。这样的最佳实践在形式化后被称为设计模式。今天我们来看看它们的概念,并检查单例模式和…...

回归预测 | MATLAB实现GAM广义加性模型多输入单输出回归预测(多指标,多图)
回归预测 | MATLAB实现GAM广义加性模型多输入单输出回归预测(多指标,多图) 目录 回归预测 | MATLAB实现GAM广义加性模型多输入单输出回归预测(多指标,多图)效果一览基本介绍程序设计参考资料 效果一览 基本…...

css学习4(背景)
1、CSS中,颜色值通常以以下方式定义: 十六进制 - 如:"#ff0000"RGB - 如:"rgb(255,0,0)"颜色名称 - 如:"red" 2、background-image 属性描述了元素的背景图像. 默认情况下,背景图像进…...

二、SQL,如何实现表的创建和查询
1、新建表格(在当前数据库中新建一个表格): (1)基础语法: create table [表名]( [字段:列标签] [该列数据类型] comment [字段注释], [字段:列标签] [该列数据类型] comment [字段注释], ……,…...

大数据及软件教学与实验专业实训室建设方案
一 、系统概述 大数据及软件教学与实验大数据及软件教学与实验在现代教育中扮演重要角色,这方面的教学内容涵盖了大数据处理、数据分析、数据可视化和大数据应用等多个方面。以下是大数据及软件教学与实验的一般内容:1. 数据基础知识:教授学生…...

信创办公–基于WPS的EXCEL最佳实践系列 (公式和函数)
信创办公–基于WPS的EXCEL最佳实践系列 (公式和函数) 目录 应用背景相关知识操作步骤1、认识基本的初级函数2、相对引用,绝对引用,混合引用3、统计函数4、文本函数 应用背景 熟练掌握Excel的函数工具能让我们在日常的使用中更加方…...

【Apollo】自动驾驶感知——毫米波雷达
作者简介: 辭七七,目前大一,正在学习C/C,Java,Python等 作者主页: 七七的个人主页 文章收录专栏: 七七的闲谈 欢迎大家点赞 👍 收藏 ⭐ 加关注哦!💖…...

SpringBoot部署到腾讯云
SpringBoot部署到腾讯云 此处默认已经申请到腾讯云服务器,因为本人还没有申请域名,所以就直接使用的ip地址 XShell连接到腾讯云 主机中填写腾讯云的公网ip地址 公网ip地址在下图中找到 接下来填写服务器的用户名与密码 一般centOS用户名为rootÿ…...

Swift 协议扩展精进之路:解决 CoreData 托管实体子类的类型不匹配问题(下)
概述 在 Swift 开发语言中,各位秃头小码农们可以充分利用语法本身所带来的便利去劈荆斩棘。我们还可以恣意利用泛型、协议关联类型和协议扩展来进一步简化和优化我们复杂的代码需求。 不过,在涉及到多个子类派生于基类进行多态模拟的场景下,…...

Cilium动手实验室: 精通之旅---20.Isovalent Enterprise for Cilium: Zero Trust Visibility
Cilium动手实验室: 精通之旅---20.Isovalent Enterprise for Cilium: Zero Trust Visibility 1. 实验室环境1.1 实验室环境1.2 小测试 2. The Endor System2.1 部署应用2.2 检查现有策略 3. Cilium 策略实体3.1 创建 allow-all 网络策略3.2 在 Hubble CLI 中验证网络策略源3.3 …...

Mac软件卸载指南,简单易懂!
刚和Adobe分手,它却总在Library里给你写"回忆录"?卸载的Final Cut Pro像电子幽灵般阴魂不散?总是会有残留文件,别慌!这份Mac软件卸载指南,将用最硬核的方式教你"数字分手术"࿰…...

UR 协作机器人「三剑客」:精密轻量担当(UR7e)、全能协作主力(UR12e)、重型任务专家(UR15)
UR协作机器人正以其卓越性能在现代制造业自动化中扮演重要角色。UR7e、UR12e和UR15通过创新技术和精准设计满足了不同行业的多样化需求。其中,UR15以其速度、精度及人工智能准备能力成为自动化领域的重要突破。UR7e和UR12e则在负载规格和市场定位上不断优化…...
大学生职业发展与就业创业指导教学评价
这里是引用 作为软工2203/2204班的学生,我们非常感谢您在《大学生职业发展与就业创业指导》课程中的悉心教导。这门课程对我们即将面临实习和就业的工科学生来说至关重要,而您认真负责的教学态度,让课程的每一部分都充满了实用价值。 尤其让我…...
Device Mapper 机制
Device Mapper 机制详解 Device Mapper(简称 DM)是 Linux 内核中的一套通用块设备映射框架,为 LVM、加密磁盘、RAID 等提供底层支持。本文将详细介绍 Device Mapper 的原理、实现、内核配置、常用工具、操作测试流程,并配以详细的…...
力扣-35.搜索插入位置
题目描述 给定一个排序数组和一个目标值,在数组中找到目标值,并返回其索引。如果目标值不存在于数组中,返回它将会被按顺序插入的位置。 请必须使用时间复杂度为 O(log n) 的算法。 class Solution {public int searchInsert(int[] nums, …...
Spring是如何解决Bean的循环依赖:三级缓存机制
1、什么是 Bean 的循环依赖 在 Spring框架中,Bean 的循环依赖是指多个 Bean 之间互相持有对方引用,形成闭环依赖关系的现象。 多个 Bean 的依赖关系构成环形链路,例如: 双向依赖:Bean A 依赖 Bean B,同时 Bean B 也依赖 Bean A(A↔B)。链条循环: Bean A → Bean…...
C++.OpenGL (20/64)混合(Blending)
混合(Blending) 透明效果核心原理 #mermaid-svg-SWG0UzVfJms7Sm3e {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-SWG0UzVfJms7Sm3e .error-icon{fill:#552222;}#mermaid-svg-SWG0UzVfJms7Sm3e .error-text{fill…...
人工智能 - 在Dify、Coze、n8n、FastGPT和RAGFlow之间做出技术选型
在Dify、Coze、n8n、FastGPT和RAGFlow之间做出技术选型。这些平台各有侧重,适用场景差异显著。下面我将从核心功能定位、典型应用场景、真实体验痛点、选型决策关键点进行拆解,并提供具体场景下的推荐方案。 一、核心功能定位速览 平台核心定位技术栈亮…...