Spring bean加载过程以及循环依赖问题


准备

spring bean 加载两次 spring重新加载bean_spring bean 加载两次

ApplicationContext context = new ClassPathXmlApplicationContext("bean.xml");       
Person person = context.getBean("person", Person.class);

通过加载xml得到Spring应用上下文,随后getBean

public class AbstractApplicationContext{
    @Override
    public <T> T getBean(String name, @Nullable Class<T> requiredType) throws BeansException {
        assertBeanFactoryActive();
        return getBeanFactory().getBean(name, requiredType);
    }
}

ClassPathXmlApplicationContext重载的构造方法中刷新了容器(refresh())–后加载bean覆盖先前的bean。其中执行了刷新beanFactory(refreshBeanFactory())得到了beanFactory

bean的加载

1、首先别名转换优先

2、从缓存中获取bean的单例

三级缓存中获取(allowEarlyReference是否允许循环依赖)

为什么会有三级?

实际上单线程下面对循环依赖的问题,一个map是可以解决问题的,也就是给这个“死循环”提供一个出口,但是在多线程下,就会容易造成创建完毕的bean和未完成初始化的bean(刚好完成构造器注入未完成其他,如 setter 注入 的 bean)混合的问题。

为什么不能两级?

会存在代理对象的问题,从三级(singletonFactories)中返回 有/无 代理的bean

/** 保存 BeanName 和创建 bean 实例之间的关系 bean name --> bean instance */
    private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256);

    /** 保存 BeanName 和创建 bean 实例的工厂之间的关系 bean name --> ObjectFactory */
    private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<>(16);

    /** 保存 BeanName 和创建 bean 实例之间的关系 bean name --> bean instance */
    /** 与 singletonObjects 不同的是当一个单例 bean 被放到里面后,那么在 bean 在创建过程中,就可以通过 getBean 方法获取到,可以用来检测循环引用。 **/
    private final Map<String, Object> earlySingletonObjects = new HashMap<>(16);
protected Object getSingleton(String beanName, boolean allowEarlyReference) {
        // 尝试从一级缓存获取实例
        Object singletonObject = this.singletonObjects.get(beanName);
        //一级缓存不存在执行二级
        if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
            synchronized (this.singletonObjects) {
                // 若该 bean 正在加载则不处理
                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);
                        //删除三级缓存中的bean
                        this.singletonFactories.remove(beanName);
                    }
                }
            }
        }
        return singletonObject;
    }

3、从缓存中获取不到bean,判断工厂(parentBeanFactory )中是否含有当前 Bean 的定义

4、获取不到bean直接创建

缓存中没有,那就当场构建一个 bean 出来,可以看到 getSingleton(String beanName, ObjectFactory)

public Object getSingleton(String beanName, ObjectFactory<?> singletonFactory) {
    synchronized (this.singletonObjects) {
        Object singletonObject = this.singletonObjects.get(beanName);
        if (singletonObject == null) {
            // 记录加载状态,,以便对循环依赖进行检测
            beforeSingletonCreation(beanName);
            singletonObject = singletonFactory.getObject();
            // 移除加载状态
            afterSingletonCreation(beanName);
            addSingleton(beanName, singletonObject);
        }
        return (singletonObject != NULL_OBJECT ? singletonObject : null);
    }
}

构建 ObjectFactory ,其实是在创建一个单例 Bean

if (mbd.isSingleton()) {
    sharedInstance = getSingleton(beanName, () -> {
        try {
            // 对 JDK8 lambda 表达式熟悉的小伙伴就不会陌生了
            return createBean(beanName, mbd, args);
        }
        catch (BeansException ex) {
            destroySingleton(beanName);
            throw ex;
        }
    });
    // 划重点了
    bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
}

创建bean

  • createBean–>首先判断需要创建的bean是否可以被实例化,这个类是否可以通过类装载器来载入

-->用 BeanPostProcessors 返回代理来替代真正的实例(如果 Bean 配置了 PostProcessor,那么这里返回的是一个代理)

  • doCreateBean -->实例化
    -->检测循环依赖,是否需要提早初始化(只能解决单例Bean)
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, () -> getEarlyBeanReference(beanName, mbd, bean));
    }

1、RootBeanDefinition 是不是单例,如果是单例先移除缓存
2、实例化 bean,将 RootBeanDefinition 转换为 BeanWrapper
3、使用 MergedBeanDefinitionPostProcessor,Autowired注解 就是通过此方法实现类型的预解析;
4、解决循环依赖问题
5、在 populateBean() 中填充属性,配置在 XML 中的各种属性
6、注册到 DisposableBean 中
7、完成创建并返回 Bean 的实例

三级缓存问题

spring bean 加载两次 spring重新加载bean_加载_02