Spring 系列
- IoC 容器
- AOP
- SpringMVC
- Spring 事务
- Spring 源码故事(瞎编版)
- Spring 整体脉络
- Spring 类解析
- Spring 自定义标签解析
- Spring Scan 包扫描
- Spring 注解工具类
- Spring 别名注册
- Spring 标签解析类
- Spring ApplicationListener
- Spring messageSource
- Spring 自定义属性解析器
- Spring 排序工具
- Spring-import 注解
- Spring-定时任务
- Spring StopWatch
- Spring 元数据
- Spring 条件接口
- Spring MultiValueMap
- Spring MethodOverride
- Spring BeanDefinitionReaderUtils
- Spring PropertyPlaceholderHelper
- Spring-AnnotationFormatterFactory
- Spring-Formatter
- Spring-Parser
- Spring-Printer
- Spring5 新特性
- Spring RMI
- Spring Message
- SpringBoot
- SpringBootBatch
- Spring Cloud
- SpringSecurity
MyBatis
- 基础支持层
- 核心处理层
- 类解析
Netty
- 网络 IO 技术基础
- JDK1.8 NIO 包 核心组件源码剖析
- Netty 粘拆包及解决方案
- Netty 多协议开发
- 基于 Netty 开发服务端及客户端
- Netty 主要组件的源码分析
- Netty 高级特性
- Netty 技术细节源码分析
Dubbo
- 架构设计
- SPI 机制
- 注册中心
- 远程通信
- RPC
- 集群
Tomcat
- Servlet 与 Servlet 容器
- Web 容器
Redis
Nacos
Sentinel
RocketMQ
- RocketMQ NameServer 与 Broker 的通信
- RocketMQ 生产者启动流程
- RocketMQ 消息发送流程
- RocketMQ 消息发送存储流程
- RocketMQ MappedFile 内存映射文件详解
- RocketMQ ConsumeQueue 详解
- RocketMQ CommitLog 详解
- RocketMQ IndexFile 详解
- RocketMQ 消费者启动流程
- RocketMQ 消息拉取流程
- RocketMQ Broker 处理拉取消息请求流程
- RocketMQ 消息消费流程
番外篇(JDK 1.8)
- 基础类库
- 集合
- 并发编程
学习心得
文章来源于网络收集而来,版权归原创者所有,如有侵权请及时联系!
循环依赖
循环依赖
一个对象依赖对象闭环到自己
A -> B -> .... ->A
tip:
不涉及代理对象问题
解决方法:当一个对象已经实例化完毕了,还未初始化的时候,将它注入到它所依赖的已经实例好的对象(提前暴露对象),使得它所依赖的对象是个完整对象(实例化+初始化),然后再将这个完整对象注入给它。
简单工程(Spring-version-5.3.18)
我们就用下面两个类进行实践,多个类间依赖也是如此。
A 类
package cn.demo1;
import lombok.Getter;
import lombok.Setter;
@Setter
@Getter
public class A {
private B b;
}
B 类
package cn.demo1;
import lombok.Getter;
import lombok.Setter;
@Setter
@Getter
public class B {
private A a;
}
配置文件 test1.xml
<?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="a" class="cn.demo1.A">
<property name="b" ref="b"/>
</bean>
<bean id="b" class="cn.demo1.B">
<property name="a" ref="a"/>
</bean>
</beans>
DefaultSingletonBeanRegistry 类中的几个特别重要的属性
// 一级缓存 存放完整Bean对象(实例化+初始化)
private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256);
// 三级缓存 存放一个lambda表达式
private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<>(16);
// 二级缓存 存放一个半成品bean对象(只是实例化还未初始化),提前暴露
private final Map<String, Object> earlySingletonObjects = new ConcurrentHashMap<>(16);
循环依赖问题应该是出现属性填充的时候
doCreateBean 这个方法
可以参照 createBeanInstance 查看 Spring 是怎么实例化的
protected Object doCreateBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)
throws BeanCreationException {
// bean的包装类
BeanWrapper instanceWrapper = null;
if (mbd.isSingleton()) {
instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);
}
if (instanceWrapper == null) {
// 就只是bean的实例化
instanceWrapper = createBeanInstance(beanName, mbd, args);
}
Object bean = instanceWrapper.getWrappedInstance();
Class<?> beanType = instanceWrapper.getWrappedClass();
if (beanType != NullBean.class) {
mbd.resolvedTargetType = beanType;
}
// 一般为true
boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences &&isSingletonCurrentlyInCreation(beanName));
// ....省略部分
if (earlySingletonExposure) {
// 这里是将一段lambda放入三级缓存中,可以看见bean填充属性之前会将三级缓存创建好,它传入了一个还未初始化的bean
addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
}
Object exposedObject = bean;
try {
populateBean(beanName, mbd, instanceWrapper);
exposedObject = initializeBean(beanName, exposedObject, mbd);
}
// ..........省略部分
return exposedObject;
}
addSingletonFactory
// 其中singletonFactory是一个lambda表达式
protected void addSingletonFactory(String beanName, ObjectFactory<?> singletonFactory) {
Assert.notNull(singletonFactory, "Singleton factory must not be null");
synchronized (this.singletonObjects) {
// 如果我们一级缓存中不存在这个叫beanName的bean
if (!this.singletonObjects.containsKey(beanName)) {
// 放入三级缓存中
this.singletonFactories.put(beanName, singletonFactory);
// 把二级缓存中叫beanName的半成品bean删除
this.earlySingletonObjects.remove(beanName);
// 标记当前注册的bean
this.registeredSingletons.add(beanName);
}
}
}
lambda 所执行的方法
protected Object getEarlyBeanReference(String beanName, RootBeanDefinition mbd, Object bean) {
Object exposedObject = bean;
// 普通bean是进不来的
if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
for (SmartInstantiationAwareBeanPostProcessor bp : getBeanPostProcessorCache().smartInstantiationAware) {
exposedObject = bp.getEarlyBeanReference(exposedObject, beanName);
}
}
// 直接返回传进来的bean,返回的是一个还未初始化的bean,是提前暴露的
return exposedObject;
}
populateBean 中有调用了 applyPropertyValues 这个方法具体详情请点击这里 applyProertyValues
protected void applyPropertyValues(String beanName, BeanDefinition mbd, BeanWrapper bw, PropertyValues pvs) {
// Create a deep copy, resolving any references for values.
List<PropertyValue> deepCopy = new ArrayList<>(original.size());
boolean resolveNecessary = false;
for (PropertyValue pv : original) {
if (pv.isConverted()) {
deepCopy.add(pv);
}
else {
// 属性名字
String propertyName = pv.getName();
//当你引用另一个bean的时候,会把它封装成RuntimeBeanReference这个对象,便于操作
Object originalValue = pv.getValue();
// 这里是解析的工作,也就是会产生循环依赖产生的地方
Object resolvedValue = valueResolver.resolveValueIfNecessary(pv, originalValue);
// 省略....
}
}
applyPropertyValues 中有个重要的方法调用,省略无关代码
// 我们当前需要要的就是
public Object resolveValueIfNecessary(Object argName, @Nullable Object value) {
// 当前bean的属性值的类型正是这个
if (value instanceof RuntimeBeanReference) {
RuntimeBeanReference ref = (RuntimeBeanReference) value;
return resolveReference(argName, ref);
}
// 省略...
}
resolveReferance 中有一段代码
// 这个方法会调用getBean
@Nullable
private Object resolveReference(Object argName, RuntimeBeanReference ref) {
// 省略...
// 上面一般进不去,直接看这个重点
resolvedName = String.valueOf(doEvaluate(ref.getBeanName()));
// 获取所依赖的bean
bean = this.beanFactory.getBean(resolvedName);
// 省略...
}
getBean 从而到这个 doGetBean 方法,其他代码不多说,最主要是下面这个
其中有一段代码,首先它会尝试从缓存中获取到 bean,如果获取不到就创建这个 bean
Object sharedInstance = getSingleton(beanName);
获取缓存 bean 的顺序是,先从一级缓存中取,若不存在,从二级缓存中取,若还是不存在,则从三级缓存中取
@Nullable
protected Object getSingleton(String beanName, boolean allowEarlyReference) {
// 一级缓存中是否存在
Object singletonObject = this.singletonObjects.get(beanName);
// 如果想要获取的bean正在创建中且无一级缓存
if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
// 尝试二级缓存
singletonObject = this.earlySingletonObjects.get(beanName);
if (singletonObject == null && allowEarlyReference) {
synchronized (this.singletonObjects) {
singletonObject = this.singletonObjects.get(beanName);
if (singletonObject == null) {
// 获取二级缓存
singletonObject = this.earlySingletonObjects.get(beanName);
if (singletonObject == null) {
// 获取三级缓存
ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
if (singletonFactory != null) {
// 调用三级缓存,这个地方就会调用我们的lambda表达式了
/**
*() -> getEarlyBeanReference(beanName, mbd, bean)
*这里就是我们解决办法的地方,因为所有普通的bean会首先提前进行三级缓存
*所以这里会获取到还未初始化的bean,从而赋值到所依赖当前singletonObject对象的bean
*/
singletonObject = singletonFactory.getObject();
// 放入二级缓存中
this.earlySingletonObjects.put(beanName, singletonObject);
// 三级缓存中移除当前beanName的lambda表达式
this.singletonFactories.remove(beanName);
}
}
}
}
}
}
// 完整对象或者还未初始化的对象
return singletonObject;
}
最后经历这个就获取到一个半成品对象所依赖的一个完整对象,然后再将完整对象注入半成品对象中。
历程
该历程仅代表当前这个项目工程
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论