现象
- 两个类都是spring的单例类,两个类里面有一个成员变量,变量都是对方。
@Component
public class BeanA
{
@Resource
private BeanB beanB;
}
@Component
class BeanB
{
@Resource
private BeanA beanA;
}
这个问题不是什么复杂的问题。正常思路是这样的。
BeanA a = new BeanA();
BeanB b = new BeanB();
a.setBeanB(b);
b.setBeanA(a);
spring 创建对象
spring的思路是这样子的,这个就出现了循环依赖的问题
public static BeanA createA() {
BeanA beanA = new BeanA();
BeanB b = createB();
beanA.setBeanB(b);
return beanA;
}
public static BeanB createB() {
BeanB beanB = new BeanB();
BeanA a = createA();
beanB.setBeanA(a);
return beanB;
}
spring的理念是,只要你创建一个对象,那么这个对象中的需要自动注入的属性就要即时注入,如果没有就创建这个属性,或者报错。
- spring的解决方式(引入缓存)伪代码
private static Map<String,Object> cacheObjects = new HashMap<>();
public static BeanA createA() {
// 先从缓存中获取
BeanA beanA = (BeanA) cacheObjects.get("beanA");
if (beanA != null){
return beanA;
}
beanA = new BeanA();
cacheObjects.put("beanA",beanA);
BeanB b = createB();
beanA.setBeanB(b);
return beanA;
}
public static BeanB createB() {
// 先从缓存中获取
BeanB beanB = (BeanB) cacheObjects.get("beanB");
if (beanB != null){
return beanB;
}
beanB = new BeanB();
cacheObjects.put("beanB",beanB);
BeanA a = createA();
beanB.setBeanA(a);
return beanB;
}
源码解读
流程图
- 先尝试从缓存中拿取实例
// 从缓存中拿取实例
Object sharedInstance = getSingleton(beanName);
缓存容器
/** Cache of singleton factories: bean name to ObjectFactory. */
private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<>(16);
从缓存中先尝试获取
....
Object singletonObject = null;
// 从三级缓存中获取实例
ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
if (singletonFactory != null) {
singletonObject = singletonFactory.getObject();
}
return singletonObject;
....
如果对象不存在创建一个对象
// 创建实例
instanceWrapper = createBeanInstance(beanName, mbd, args);
创建对象之后加入缓存,注意这个对象是一个空的对象。
之后来进行属性注入
// 获取有@AutoWired 注解的字段和方法
InjectionMetadata metadata = findAutowiringMetadata(beanName, bean.getClass(), pvs);
try {
// 进行设置值
metadata.inject(bean, beanName, pvs);
}
// 获取依赖注入的值
value = beanFactory.resolveDependency(desc, beanName, autowiredBeanNames, typeConverter);
如果它是一个对象类型的数据,最终触发getBean操作
public Object resolveCandidate(String beanName, Class<?> requiredType, BeanFactory beanFactory)
throws BeansException {
return beanFactory.getBean(beanName);
}