Spring处理循环依赖只使用二级缓存可以吗?(二)
我还是把上面的例子改进一下,改成用3级缓存的实现
public interface ObjectFactory<T> {
T getObject();
}
public class DependencyDemoV3 {
private static final Map<String, Object> singletonObjects =
new HashMap<>(256);
private static final Map<String, Object> earlySingletonObjects =
new HashMap<>(256);
private static final Map<String, ObjectFactory<?>> singletonFactories =
new HashMap<>(256);
@SneakyThrows
public static <T> T getBean(Class<T> beanClass) {
String beanName = beanClass.getSimpleName();
if (singletonObjects.containsKey(beanName)) {
return (T) singletonObjects.get(beanName);
}
if (earlySingletonObjects.containsKey(beanName)) {
return (T) earlySingletonObjects.get(beanName);
}
ObjectFactory<?> singletonFactory = singletonFactories.get(beanName);
if (singletonFactory != null) {
return (T) singletonFactory.getObject();
}
// 实例化bean
Object object = beanClass.getDeclaredConstructor().newInstance();
singletonFactories.put(beanName, () -> {
Object proxy = createProxy(object);
singletonFactories.remove(beanName);
earlySingletonObjects.put(beanName, proxy);
return proxy;
});
// 开始初始化bean,即填充属性
Field[] fields = object.getClass().getDeclaredFields();
for (Field field : fields) {
field.setAccessible(true);
// 获取需要注入字段的class
Class<?> fieldClass = field.getType();
field.set(object, getBean(fieldClass));
}
createProxy(object);
singletonObjects.put(beanName, object);
singletonFactories.remove(beanName);
earlySingletonObjects.remove(beanName);
return (T) object;
}
public static Object createProxy(Object object) {
// 因为这个方法有可能被执行2次,所以这里应该有个判断
// 如果之前提前进行过aop操作则直接返回,知道意思就行,不写了哈
// 需要aop的话则返回代理对象,否则返回传入的对象
return object;
}
public static void main(String[] args) {
// 假装扫描出来的类
Class[] classes = {A.class, B.class};
for (Class aClass : classes) {
getBean(aClass);
}
System.out.println(getBean(A.class).getB() == getBean(B.class));
System.out.println(getBean(B.class).getA() == getBean(A.class));
}
}
「为什么要包装一个ObjectFactory对象?」
如果创建的Bean有对应的aop代理,那其他对象注入时,注入的应该是对应的代理对象;「但是Spring无法提前知道这个对象是不是有循环依赖的情况」,而正常情况下(没有循环依赖情况),Spring都是在对象初始化后才创建对应的代理。这时候Spring有两个选择:
- 不管有没有循环依赖,实例化后就直接创建好代理对象,并将代理对象放入缓存,出现循环依赖时,其他对象直接就可以取到代理对象并注入(只需要2级缓存,singletonObjects和earlySingletonObjects即可)
- 「不提前创建好代理对象,在出现循环依赖被其他对象注入时,才提前生成代理对象(此时只完成了实例化)。这样在没有循环依赖的情况下,Bean还是在初始化完成才生成代理对象」(需要3级缓存)
「所以到现在为止你知道3级缓存的作用了把,主要是为了正常情况下,代理对象能在初始化完成后生成,而不用提前生成」
源码解析
获取Bean的时候先尝试从3级缓存中获取,和我们上面的Demo差不多哈
DefaultSingletonBeanRegistry#getSingleton
当从缓存中获取不到时,会进行创建 AbstractAutowireCapableBeanFactory#doCreateBean(删除了部分代码哈)
发生循环依赖时,会从工厂里获取代理对象哈
当开启aop代理时,SmartInstantiationAwareBeanPostProcessor的一个实现类有AbstractAutoProxyCreator
AbstractAutoProxyCreator#getEarlyBeanReference
getEarlyBeanReference方法提前进行代理,为了防止后面再次进行代理,需要用earlyProxyReferences记录一下,这个Bean已经被代理过了,不用再代理了
AbstractAutoProxyCreator#postProcessAfterInitialization
这个方法是进行aop代理的地方,因为有可能提前代理了,所以先根据earlyProxyReferences判断一下,是否提前代理了,提前代理过就不用代理了
当bean初始化完毕,会放入一级缓存,并从二三级缓存删除
DefaultSingletonBeanRegistry#addSingleton
发生循环依赖时,整体的执行流程如下
文章转自公众号:Java识堂