java 注入 循环_spring依赖注入——循环依赖
上一篇博客简单地分析了下依赖注入。但是对于依赖注入的很多细节,都没有深入的分析。这一篇博客会继续分析spring的依赖注入。这篇博客会解决分析getBean缓存时候遗留下来的循环依赖问题。
循环依赖分析
首先明确下,只有单例情况下,spring才会试着去解决循环依赖问题,多例是不会去解决循环依赖的。这个也好理解,如果是多例的话,比如a -> b 并且 b -> a 那么,当A a=new A(); 之后要注入b,b却是多例的,那么究竟该注入哪个B是不确定的。如下图:
接下来我们分析,为啥会有循环依赖的问题。
先来分析没有循环依赖的问题public static class A{
private B b; //省略get和set方法}public static class B{
}
这个时候,如果spring先初始化A,然后会发现A依赖于B,然后就会初始化B,最后注入到A里。
整个流程用代码表示大概如下所示:A a = 创建A
B b = 创建B
-----> 创建A子流程 a.setB(b);
但是假设B也依赖了A呢?即public static class B{
private A a;
}
那样依赖注入过程就会变成(简单示例)A a = 创建A
B b = 创建B
----> 创建B子流程 b.setA(????); // 这个时候A还没创建完成呢a.setB(b);
那么如何解决呢?很简单,把那个还没创建完的A(只是new了,但是没有进行依赖注入的A)set到B里就好了。
弄清了这个流程之后,我们再来分析spring是如何进行依赖注入的。
spring对引用类型的注入
这里我先从spring对引用属性的注入开始。
即ref的注入private Object resolveReference(Object argName, RuntimeBeanReference ref) { try { String refName = ref.getBeanName();
refName = String.valueOf(doEvaluate(refName)); if (ref.isToParent()) { if (this.beanFactory.getParentBeanFactory() == null) { throw new BeanCreationException( this.beanDefinition.getResourceDescription(), this.beanName, "Can't resolve reference to bean '" + refName + "' in parent factory: no parent factory available");
} return this.beanFactory.getParentBeanFactory().getBean(refName);
} else { Object bean = this.beanFactory.getBean(refName); this.beanFactory.registerDependentBean(refName, this.beanName); return bean;
}
} catch (BeansException ex) { throw new BeanCreationException( this.beanDefinition.getResourceDescription(), this.beanName, "Cannot resolve reference to bean '" + ref.getBeanName() + "' while setting " + argName, ex);
}
}
实现很简单,就是从beanFactory里获取要依赖的对象
我们再来回顾下流程
问题是,当走到6时候,似乎又会回到1,这样不就死循环了么?
重点就是,第六步的获取A,我们回到doGetBean方法中。
getSingleton 方法protected Object getSingleton(String beanName, boolean allowEarlyReference) { //已创建的对象里面找下
Object singletonObject = this.singletonObjects.get(beanName); //没找到,并且当前类正在被创建
if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) { synchronized (this.singletonObjects) {
singletonObject = this.earlySingletonObjects.get(beanName); if (singletonObject == null && allowEarlyReference) {
ObjectFactory> singletonFactory = this.singletonFactories.get(beanName); if (singletonFactory != null) {
singletonObject = singletonFactory.getObject(); this.earlySingletonObjects.put(beanName, singletonObject); this.singletonFactories.remove(beanName);
}
}
}
} return (singletonObject != NULL_OBJECT ? singletonObject : null);
}
我们在分析初始化bean的缓存部分时,曾分析过这几个缓存。当时其实只知道了singletonObjects是存储了已经创建了的对象。
现在让我们回头再看看这些缓存。
首先看看singletonFactories赋值的地方。
doCreateBean// 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.isDebugEnabled()) {
logger.debug("Eagerly caching bean '" + beanName + "' to allow for resolving potential circular references");
}
addSingletonFactory(beanName, new ObjectFactory() { @Override
public Object getObject() throws BeansException { //默认实现返回bean
return getEarlyBeanReference(beanName, mbd, bean);
}
});
}
在创建bean时候,有这样一段代码,当需要进行提前暴露时候(当前创建对象单例 + 允许循环引用 + 当前类正在被创建)会调用addSingletonFactory方法protected void addSingletonFactory(String beanName, ObjectFactory> singletonFactory) {
Assert.notNull(singletonFactory, "Singleton factory must not be null"); synchronized (this.singletonObjects) { if (!this.singletonObjects.containsKey(beanName)) { this.singletonFactories.put(beanName, singletonFactory); this.earlySingletonObjects.remove(beanName); this.registeredSingletons.add(beanName);
}
}
}
这里就碰见了我们要分析的singletonFactories,它存储了beanName -> 此处的匿名内部类singletonFactory。
singletonFactory
我们再回到getSingleton方法,以及之前绘制的图ObjectFactory> singletonFactory = this.singletonFactories.get(beanName);if (singletonFactory != null) {
singletonObject = singletonFactory.getObject(); this.earlySingletonObjects.put(beanName, singletonObject); this.singletonFactories.remove(beanName);
}
逻辑很简单
三级缓存
我们经常听说spring通过三级缓存解决了循环依赖,其实三级缓存非常简单。就是指我们分析过的Map singletonObjects
Map> singletonFactories
Map earlySingletonObjects
这里分别举这样三个例子。
A 依赖 B(B不依赖A)
一级缓存
A 依赖 B && B依赖A
三级缓存
A依赖B && B依赖A + B依赖C && C 依赖 A
作者:端吉
链接:https://www.jianshu.com/p/10f94b776e55
java 注入 循环_spring依赖注入——循环依赖相关推荐
- spring 循环依赖注入
什么是循环依赖 循环依赖就是循环引用,就是两个或多个Bean相互之间的持有对方,比如A引用B,B引用C,C引用A,则它们最终反映为一个环. spring 中循环依赖注入分三种情况 1. 构造器循环依赖 ...
- Spring 依赖注入三种方式的实现,及循环依赖问题的解决(源码+XML配置)
搬砖啦,搬砖啦,这几天在看Spring相关的书,下面给大家分享一下这几天的心得与收获,Go Go Go! Spring支持两种依赖注入方式,分别是属性注入,构造函数注入.除此之外,Spring还支持工 ...
- java循环依赖问题怎么解决_Spring如何解决循环依赖的问题
前言 在面试的时候这两年有一个非常高频的关于spring的问题,那就是spring是如何解决循环依赖的.这个问题听着就是轻描淡写的一句话,其实考察的内容还是非常多的,主要还是考察的应聘者有没有研究过s ...
- Spring依赖注入和循环依赖问题分析
Spring源码揭秘之依赖注入和循环依赖问题分析 前言 依赖注入的入口方法 依赖注入流程分析 AbstractBeanFactory#getBean AbstractBeanFactory#doGet ...
- 6. 以下耦合度中最松散的耦合是_Spring Java中的依赖注入,它是如何工作的?- 知识铺...
知识铺: 致力于打造轻知识点,持续更新每次的知识点较少,阅读不累.不占太多时间,不停地来唤醒记忆深处的知识点. 一.Spring 框架 POJO Spring Framework是一个开源的应用程序框 ...
- Android mock for循环,Android单元测试(五):依赖注入,将mock方便的用起来
在上一篇文章中,咱们讲了要将mock出来的dependency真正使用起来,须要在测试环境下经过某种方式set 到用到它的那个对象里面进去,替换掉真实的实现.咱们前面举的例子是:html public ...
- java什么是依赖注入_spring的依赖注入是什么意思
最近学习spring框架,对依赖注入有些模糊,遂上网翻阅资料,做了下列总结,原博客为CSDN 南夏的 spring的依赖注入是什么意思,侵删! Spring 能有效地组织J2EE应用各层的对象.不管是 ...
- java 构造器注入_Spring学习笔记1—依赖注入(构造器注入、set注入和注解注入)...
什么是依赖注入 在以前的java开发中,某个类中需要依赖其它类的方法时,通常是new一个依赖类再调用类实例的方法,这种方法耦合度太高并且不容易测试,spring提出了依赖注入的思想,即依赖类不由程序员 ...
- Java 依赖注入标准(JSR-330)简介
Java 依赖注入标准(JSR-330)简介 转载请保留作者信息: 作者:88250 ,Vanessa 时间:2009 年 11 月 19 日 Java 依赖注入标准(JSR-330,Dependen ...
最新文章
- 取代Python多进程!伯克利开源分布式框架Ray
- React从入门到精通系列之(1)安装React
- Linux数据报文接收发送总结3
- [导入]C#面向对象设计模式纵横谈(17):(行为型模式) Mediator 中介者模式.zip(8.75 MB)...
- How to get user parameter settings
- BZOJ2818-莫比乌斯反演/欧拉函数
- LintCode 795. 4种独特的路径(DFS)
- 【第二组】项目冲刺(Alpha版本)第三次每日例会 2017/7/13
- xclip linux_使用xclip在Linux命令行中复制和粘贴
- HDU1754 I Hate It (线段树单点修改+区间查询)
- java面向对象简介
- IDEA上的文字转拼音名
- python中ctype的应用,协议解析,C语言与python的完美映射,结构体与字符串的相互转换
- (七)HyperledgerFarbic1.4- Fabric的SDK使用
- Python做一份简易旅行攻略——疫情之后,若条件允许,可愿意用一场旅行“弥补”自己
- 明年债券收益率有望延续下行的趋势
- 电缆公司如何面对企业改革?MES系统打造智能工厂
- 08 量子力学教材推荐,量子力学书单:量子力学、高等量子力学、量子统计、量子信息、路径积分...(适合物理专业本科生、研究生、物理爱好者)
- PSD文件生成Unity预设
- 西方科学家依然对互联网的进化表示质疑
热门文章
- 前端学习(1):HTML和CSS导学
- CM3计算板EC20模组拨号上网
- eclipse启动报错No java virtual machine was found after seearching the locations:XXXXX
- :after伪类+content内容清除浮动
- 二维数组排序 行与列分别升序_6个经典排序技巧,尤其是最后一个,绝对的个性化...
- 百度地图gif图标_华为手机误删照片怎么找回?手机怎么快速制作GIF动图
- 第八届蓝桥杯-日期问题
- redis 超时失效key 的监听触发
- 【卡法电子商务】-常用手机屏幕尺寸 ★★★★★
- HDU 1394 线段树or 树状数组~