什么是循环依赖
所谓的循环依赖是指,A 依赖 B,B 又依赖 A,它们之间形成了循环依赖。或者是 A 依赖 B,B 依赖 C,C 又依
赖 A。它们之间的依赖关系如下
代码示例:
public class MainStart {
private static Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<>(256);
/**
* 读取bean定义,当然在spring中肯定是根据配置 动态扫描注册
*/
public static void loadBeanDefinitions() {
RootBeanDefinition aBeanDefinition=new RootBeanDefinition(InstanceA.class);
RootBeanDefinition bBeanDefinition=new RootBeanDefinition(InstanceB.class);
beanDefinitionMap.put("instanceA",aBeanDefinition);
beanDefinitionMap.put("instanceB",bBeanDefinition);
}
public static void main(String[] args) throws Exception {
// 加载了BeanDefinition
loadBeanDefinitions();
// 注册Bean的后置处理器
// 循环创建Bean
for (String key : beanDefinitionMap.keySet()){
// 先创建A
getBean(key);
}
InstanceA instanceA = (InstanceA) getBean("instanceA");
instanceA.say();
}
// 一级缓存
public static Map<String,Object> singletonObjects=new ConcurrentHashMap<>();
// 二级缓存: 为了将 成熟Bean和纯净Bean分离,避免读取到不完整得Bean
public static Map<String,Object> earlySingletonObjects=new ConcurrentHashMap<>();
// 三级缓存
public static Map<String,ObjectFactory> singletonFactories=new ConcurrentHashMap<>();
// 循环依赖标识
public static Set<String> singletonsCurrennlyInCreation=new HashSet<>();
// 假设A 使用了Aop @PointCut("execution(* *..InstanceA.*(..))") 要给A创建动态代理
// 获取Bean
public static Object getBean(String beanName) throws Exception {
Object singleton = getSingleton(beanName);
if(singleton!=null){
return singleton;
}
// 正在创建
if(!singletonsCurrennlyInCreation.contains(beanName)){
singletonsCurrennlyInCreation.add(beanName);
}
// createBean
// 实例化
RootBeanDefinition beanDefinition = (RootBeanDefinition) beanDefinitionMap.get(beanName);
Class<?> beanClass = beanDefinition.getBeanClass();
Object instanceBean = beanClass.newInstance(); // 通过无参构造函数
// 创建动态代理 (耦合 、BeanPostProcessor) Spring还是希望正常的Bean 还是再初始化后创建
// 只在循环依赖的情况下在实例化后创建proxy 判断当前是不是循环依赖
singletonFactories.put(beanName, () -> new JdkProxyBeanPostProcessor().getEarlyBeanReference(earlySingletonObjects.get(beanName),beanName));
// 添加到二级缓存
// earlySingletonObjects.put(beanName,instanceBean);
// 属性赋值
Field[] declaredFields = beanClass.getDeclaredFields();
for (Field declaredField : declaredFields) {
Autowired annotation = declaredField.getAnnotation(Autowired.class);
// 说明属性上面有Autowired
if(annotation!=null){
declaredField.setAccessible(true);
// byname bytype byconstrator
// instanceB
String name = declaredField.getName();
Object fileObject= getBean(name); //拿到B得Bean
declaredField.set(instanceBean,fileObject);
}
}
// 初始化 init-mthod
// 放在这里创建已经完了 B里面的A 不是proxy
// 正常情况下会再 初始化之后创建proxy
// 由于递归完后A 还是原实例,, 所以要从二级缓存中拿到proxy 。
if(earlySingletonObjects.containsKey(beanName)){
instanceBean=earlySingletonObjects.get(beanName);
}
// 添加到一级缓存 A
singletonObjects.put(beanName,instanceBean);
// remove 二级缓存和三级缓存
return instanceBean;
}
public static Object getSingleton(String beanName){
// 先从一级缓存中拿
Object bean = singletonObjects.get(beanName);
// 说明是循环依赖
if(bean==null && singletonsCurrennlyInCreation.contains(beanName)){
bean=earlySingletonObjects.get(beanName);
// 如果二级缓存没有就从三级缓存中拿
if(bean==null) {
// 从三级缓存中拿
ObjectFactory factory = singletonFactories.get(beanName);
if (factory != null) {
bean=factory.getObject(); // 拿到动态代理
earlySingletonObjects.put(beanName, bean);
}
}
}
return bean;
}
}
总结:getBean()核心方法
1:先实例化化,采用反射无参构造Object beanInstanc = beanClass.newInstance();
2:获取filed 对filed 赋值,递归调用getBean方法Object fileObject= getBean(name);
3:将bean 放到 一级缓存singletonObjects.put(beanName,instanceBean);
如何解决循环依赖
三级缓存
一级缓存
保存的是单实例的beanprivate final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256);
二级缓存
缓存的是早期对象,不完整的bean对象private final Map<String, Object> earlySingletonObjects = new HashMap<>(16);
三级缓存
缓存的是 ObjectFactoryprivate final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<>(16);
创建的步骤
创建原始 bean 对象
instanceWrapper = createBeanInstance(beanName, mbd, args);
final Object bean = (instanceWrapper != null ? instanceWrapper.getWrappedInstance() : null);
暴露早期的引用
把早期对象包装称ObjectFactory 放在三级缓存- 解析依赖
populateBean(beanName, mbd, instanceWrapper);
对对象A填充属性B,会调用BeanFactory.getBean(方法 - 获取早期引用
this.earlySingletonObjects.get("beanA")
org.springframework.beans.factory.support.DefaultSingletonBeanRegistry#getSingleton(java.lang.String, boolean)
protected Object getSingleton(String beanName, boolean allowEarlyReference) {
// Quick check for existing instance without full singleton lock
// 从单例对象缓存中获取beanName对应的单例对象
Object singletonObject = this.singletonObjects.get(beanName);
// 如果单例对象缓存中没有,并且该beanName对应的单例bean正在创建中
if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
//从早期单例对象缓存中获取单例对象(之所称成为早期单例对象,是因为earlySingletonObjects里
// 的对象的都是通过提前曝光的ObjectFactory创建出来的,还未进行属性填充等操作)
singletonObject = this.earlySingletonObjects.get(beanName);
// 如果在早期单例对象缓存中也没有,并且允许创建早期单例对象引用
if (singletonObject == null && allowEarlyReference) {
// 如果为空,则锁定全局变量并进行处理
synchronized (this.singletonObjects) {
// Consistent creation of early reference within full singleton lock
singletonObject = this.singletonObjects.get(beanName);
if (singletonObject == null) {
singletonObject = this.earlySingletonObjects.get(beanName);
if (singletonObject == null) {
// 当某些方法需要提前初始化的时候则会调用addSingletonFactory方法将对应的ObjectFactory初始化策略存储在singletonFactories
ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
if (singletonFactory != null) {
// 如果存在单例对象工厂,则通过工厂创建一个单例对象
singletonObject = singletonFactory.getObject();
// 记录在缓存中,二级缓存和三级缓存的对象不能同时存在
this.earlySingletonObjects.put(beanName, singletonObject);
// 从三级缓存中移除
this.singletonFactories.remove(beanName);
}
}
}
}
}
}
return singletonObject;
}
对应过程的流程图
https://www.processon.com/view/link/5f1fb2cf1e08533a628a7b4c
三级缓存的原因
二级缓存:分离完整bean和初始化bean,多线程下要保证getBean是完整bean
为什么三级:
bean的aop实在初始化之后,
如果循环依赖Bean使用aop,需要提前创建aop
三级缓存,是一个函数接口,代理对象,普通对象都在BeanPostProcessore,可以解耦,
?我在看看吧
spring不能解决构造器的循环依赖:
实例化之前,缓存没有bean的信息,也就取不到
多例不能解决循环依赖:
如果是原型bean: 每次都有创建对象
如果是构造注入,需要调用构造注入,无法利用缓存
循环依赖的关闭功能
public class Main {
public static void main(String[] args) {
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();
applicationContext.setAllowCircularReferences(false);
applicationContext.register(AppConfig.class);
applicationContext.refresh();
}
}
如何扩展
SmartInstantiationAwareBeanPostProcessor 重写 getEarlyBeanReference
protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final Object[] args)throws BeanCreationException {
//省略其他代码,只保留了关键代码
//...
// 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");
}
//将刚实例化好的bean添加到一级缓存中
addSingletonFactory(beanName, new ObjectFactory
@Override
public Object getObject()throws BeansException {
//执行拓展的后置处理器
return getEarlyBeanReference(beanName, mbd, bean);
}
});
}
}
getEarlyBeanRerence方法
protected Object getEarlyBeanReference(String beanName, RootBeanDefinition mbd, Object bean) {
Object exposedObject = bean;
//判读我们容器中是否有InstantiationAwareBeanPostProcessors类型的后置处理器
if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
//获取我们所有的后置处理器
for (BeanPostProcessor bp : getBeanPostProcessors()) {
//判断我们的后置处理器是不是实现了SmartInstantiationAwareBeanPostProcessor接口
if (bp instanceof SmartInstantiationAwareBeanPostProcessor) {
//进行强制转换
SmartInstantiationAwareBeanPostProcessor ibp = (SmartInstantiationAwareBeanPostProcessor) bp;
//挨个调用SmartInstantiationAwareBeanPostProcessor的getEarlyBeanReference
exposedObject = ibp.getEarlyBeanReference(exposedObject, beanName);
}
}
}
return exposedObject;
}
扩展实例code
@Component
public class TulingBPP implements SmartInstantiationAwareBeanPostProcessor {
public Object getEarlyBeanReference(Object bean, String beanName) throws BeansException {
if(beanName.equals("instanceA") || beanName.equals("instanceB")) {
JdkDynimcProxy jdkDynimcProxy = new JdkDynimcProxy(bean);
return jdkDynimcProxy.getProxy();
}
return bean;
}
}
还得自己多看code
源码入口:
// 初始化剩下的单实例(非懒加载的)
finishBeanFactoryInitialization(beanFactory);