天天看点

spring ioc源码解析-启动流程与循环依赖使用示例启动流程创建bean三级缓存与循环依赖

使用示例

读源码先从最简单的使用示例入手,然后一层一层往下探索,下面先写一个典型的spring小例子,来看一下它的入口与使用方法:

//创建User类
public class User {
    private String name;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}
           
//定义XML文件:user.xml
//省略spring配置文件头
......
<bean name="user" class="User">
    <property name="name" value="test"/>
</bean>
           
//使用示例:
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("user.xml");
User user = (User)applicationContext.getBean("user");
System.out.println(user.getName());
           

整个例子非常简单,就是创建一个User Bean,然后获得它的name,下面我们从入口

ClassPathXmlApplicationContext开始来了解Spring的启动流程。

启动流程

ClassPathXmlApplicationContext构造方法如下:

public ClassPathXmlApplicationContext(String[] configLocations, boolean refresh, ApplicationContext parent)
			throws BeansException {

		super(parent);
        //设置xml配置文件
		setConfigLocations(configLocations);
		if (refresh) {
      //启动
			refresh();
		}
	}
           

接下来看启动核心方法refresh():

public void refresh() throws BeansException, IllegalStateException {
  synchronized (this.startupShutdownMonitor) {
    //主要是校验配置与参数
    // Prepare this context for refreshing.
    prepareRefresh();

    //创建一个BeanFactory,用于创建bean
    // Tell the subclass to refresh the internal bean factory.
    ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();

    //初始化beanFactory, 主要是准备创建bean时需要的环境与关系,并且会创建几个初始bean
    // Prepare the bean factory for use in this context.
    prepareBeanFactory(beanFactory);

    try {
      //允许子类设置postProcessor
      //ClassPathXmlApplicationContext是spring基础的ApplicationContext,所以不需要设置特有功能的postprocessor
      //像webApplicationContext则需要把servlet相关的processor设置进来,用来支撑spring mvc相关功能
      // Allows post-processing of the bean factory in context subclasses.
      postProcessBeanFactory(beanFactory);

      //实例化processor  并注册到beanfactory中
      //这里的processor主要是通过AbstractApplicationContext类addBeanFactoryPostProcessor方法设置进来的。
      // Invoke factory processors registered as beans in the context.
      invokeBeanFactoryPostProcessors(beanFactory);

      //实例化processor  并注册到beanfactory中
      //这里processor主要是spring本身自带的
      // Register bean processors that intercept bean creation.
      registerBeanPostProcessors(beanFactory);

      //初始化message source并注册成bean,用于消息解析相关
      // Initialize message source for this context.
      initMessageSource();

      //初始化事件广播器
      // Initialize event multicaster for this context.
      initApplicationEventMulticaster();

      //子类刷新使用
      // Initialize other special beans in specific context subclasses.
      onRefresh();

      //注册监听器,eventMulticaster广播之前产生的事件
      // Check for listener beans and register them.
      registerListeners();

      //完成beanfactory初始化,确保所有单例bean完成加载,
      //主要是通过getBean方法一个一个检查,为空时就创建bean
      // Instantiate all remaining (non-lazy-init) singletons.
      finishBeanFactoryInitialization(beanFactory);

      //发布容器刷新完成事件,主要内容是定义生命周期的Bean
      // Last step: publish corresponding event.
      finishRefresh();
    }

    catch (BeansException ex) {
      if (logger.isWarnEnabled()) {
        logger.warn("Exception encountered during context initialization - " +
                    "cancelling refresh attempt: " + ex);
      }

      // Destroy already created singletons to avoid dangling resources.
      destroyBeans();

      // Reset 'active' flag.
      cancelRefresh(ex);

      // Propagate exception to caller.
      throw ex;
    }

    finally {
      // Reset common introspection caches in Spring's core, since we
      // might not ever need metadata for singleton beans anymore...
      resetCommonCaches();
    }
  }
}
           

通过中文注释我们大概了解了spring的启动流程,因为流程涉及到的方法比较多,所以不一一分析各个方法的源码了,简单总结一下流程是这样的:

1.检查配置与参数

2.创建一个类型为

ConfigurableListableBeanFactory的beanFactory

3.初始化该beanFactory,主要是配置环境、创建一些默认bean等

4.注册postprocessor,先扩展类processor后spring基础类processor

5.注册广播与监听bean

6.完成初始化

7.注册生命周期管理的bean

spring ioc源码解析-启动流程与循环依赖使用示例启动流程创建bean三级缓存与循环依赖

其中processor作用是创建bean时允许加入自定义的修改。上面流程中最核心的是第6步,在这一步调用getBean方法,从而真正执行创建bean的工作,接下来我们看一下创建bean的过程。

创建bean

getBean方法最终后调用AbstractBeanFactory的getBean方法,如下:

public <T> T getBean(String name, Class<T> requiredType) throws BeansException {
  return doGetBean(name, requiredType, null, false);
}
           

然后执行doGetBean:

protected <T> T doGetBean(
  final String name, final Class<T> requiredType, final Object[] args, boolean typeCheckOnly)
throws BeansException {
  ..................
  // Create bean instance.
  if (mbd.isSingleton()) {
    //从DefaultSingletonBeanRegistry的一级缓存中拿bean,如果不存在执行创建函数
    //将创建成功后bean放入到一级缓存中。
    sharedInstance = getSingleton(beanName, new ObjectFactory<Object>() {
                                  @Override
                                  public Object getObject() throws BeansException {
      try {
        //bean不存在则创建
        return createBean(beanName, mbd, args);
      }
      catch (BeansException ex) {
        // Explicitly remove instance from singleton cache: It might have been put there
        // eagerly by the creation process, to allow for circular reference resolution.
        // Also remove any beans that received a temporary reference to the bean.
        destroySingleton(beanName);
        throw ex;
      }
    }
  });
  bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
}
           

需要注意的是

DefaultSingletonBeanRegistry有三级缓存,getBean方法只是从第一级缓存中查找bean的成品。

接下来我们看createBean:

@Override
protected Object createBean(String beanName, RootBeanDefinition mbd, Object[] args) throws BeanCreationException {
  if (logger.isDebugEnabled()) {
    logger.debug("Creating instance of bean '" + beanName + "'");
  }
  RootBeanDefinition mbdToUse = mbd;

  ...............

  //执行创建bean
  Object beanInstance = doCreateBean(beanName, mbdToUse, args);
  if (logger.isDebugEnabled()) {
    logger.debug("Finished creating instance of bean '" + beanName + "'");
  }
  return beanInstance;
}
           

这样我们就进入了创建bean的核心方法doCreateBean:

protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final Object[] args)
throws BeanCreationException {

  //实例化bean
  // Instantiate the bean.
  BeanWrapper instanceWrapper = null;
  if (mbd.isSingleton()) {
    instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);
  }
  if (instanceWrapper == null) {
    //实例化
    instanceWrapper = createBeanInstance(beanName, mbd, args);
  }

  ........................

  //加入到三级缓存中
  // 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));
  //为解决依赖问题,需要提前曝光还未创建完成的bean
  if (earlySingletonExposure) {
    if (logger.isDebugEnabled()) {
      //这里的日志说得非常清楚,放在第三级缓存中是为了解决循环依赖问题 
      logger.debug("Eagerly caching bean '" + beanName +
                   "' to allow for resolving potential circular references");
    }
    //加入到三级缓存中
    addSingletonFactory(beanName, new ObjectFactory<Object>() {
                        @Override
                        public Object getObject() throws BeansException {
      return getEarlyBeanReference(beanName, mbd, bean);
    }
  });
}

//初始化:主要是设置注入的变量等
// Initialize the bean instance.
Object exposedObject = bean;
try {
  //填充属性
  populateBean(beanName, mbd, instanceWrapper);
  if (exposedObject != null) {
    //调用aware类方法,设置beanPostProcessor
    exposedObject = initializeBean(beanName, exposedObject, mbd);
  }
}

...............

return exposedObject;
}
           

这个方法有点长,我把关键的几行挑出来并用中文注释了,其实思路也挺清晰的,先创建实例再初始化最后加入到缓存中。

在doGetBean方法中,会执行getSingleton,这个方法会调用createBean,并将创建的bean加入到一级缓存中,代码如下:

public Object getSingleton(String beanName, ObjectFactory<?> singletonFactory) {
  Assert.notNull(beanName, "'beanName' must not be null");
  synchronized (this.singletonObjects) {
    Object singletonObject = this.singletonObjects.get(beanName);
    if (singletonObject == null) {
      if (this.singletonsCurrentlyInDestruction) {
        throw new BeanCreationNotAllowedException(beanName,
                                                  "Singleton bean creation not allowed while singletons of this factory are in destruction " +
                                                  "(Do not request a bean from a BeanFactory in a destroy method implementation!)");
      }
      if (logger.isDebugEnabled()) {
        logger.debug("Creating shared instance of singleton bean '" + beanName + "'");
      }
      beforeSingletonCreation(beanName);
      boolean newSingleton = false;
      boolean recordSuppressedExceptions = (this.suppressedExceptions == null);
      if (recordSuppressedExceptions) {
        this.suppressedExceptions = new LinkedHashSet<Exception>();
      }
      try {
        //执行创建bean操作:createBean()方法
        singletonObject = singletonFactory.getObject();
        newSingleton = true;
      }
      catch (IllegalStateException ex) {
        // Has the singleton object implicitly appeared in the meantime ->
        // if yes, proceed with it since the exception indicates that state.
        singletonObject = this.singletonObjects.get(beanName);
        if (singletonObject == null) {
          throw ex;
        }
      }
      catch (BeanCreationException ex) {
        if (recordSuppressedExceptions) {
          for (Exception suppressedException : this.suppressedExceptions) {
            ex.addRelatedCause(suppressedException);
          }
        }
        throw ex;
      }
      finally {
        if (recordSuppressedExceptions) {
          this.suppressedExceptions = null;
        }
        afterSingletonCreation(beanName);
      }
      if (newSingleton) {
        //加入到一级缓存中
        addSingleton(beanName, singletonObject);
      }
    }
    return (singletonObject != NULL_OBJECT ? singletonObject : null);
  }
}
           

加入缓存的代码如下:

protected void addSingleton(String beanName, Object singletonObject) {
  synchronized (this.singletonObjects) {
    //放入到一级缓存
    this.singletonObjects.put(beanName, (singletonObject != null ? singletonObject : NULL_OBJECT));
    //从三级缓存中删除
    this.singletonFactories.remove(beanName);
    //从二级缓存中删除
    this.earlySingletonObjects.remove(beanName);
    //标记该beanname已经被创建过
    this.registeredSingletons.add(beanName);
  }
}
           

上面的代码我们了解到bean的创建过程,总结如下:

getBean-> doGetBean->createBean->doCreateBean->放入一级缓存中->返回
           

当然这里主要是为了了解过程,所以很多细节被忽略了,包括两个重要功能:aop支持与循环依赖的解决,下一节将着重分析这两个功能的代码。

三级缓存与循环依赖

上文有提到

DefaultSingletonBeanRegistry中有三级缓存,用来保存不同创建阶段的bean, 第一级是bean实例化后存放的地方,此时还没有注入依赖关系,第二级则是将第一级缓存的bean进行增强后存放的地方,增强的主要内容是使用动态代理的方式使它支持AOP,最后把第二级的bean注入依赖关系后放入到第三级。

三级缓存如下:

1.第一级为bean成品:singletonObjects

/** Cache of singleton objects: bean name --> bean instance */
private final Map<String, Object> singletonObjects = new ConcurrentHashMap<String, Object>(256);
           

2.第二级:earlySingletonObjects

/** Cache of early singleton objects: bean name --> bean instance */
private final Map<String, Object> earlySingletonObjects = new HashMap<String, Object>(16);
           

3.第三级:singletonFactories

/** Cache of singleton factories: bean name --> ObjectFactory */
private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<String, ObjectFactory<?>>(16);
           

那spring是怎么利用三级缓存来解决依赖问题的呢? 在doCreateBean方法中,spring使用createBeanInstance方法创建了一个bean实例,这个实例还未进行初始化,它会先放到第三级缓存中,然后检查依赖关系,下面继续回到doCreateBean方法中:

protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final Object[] args)
throws BeanCreationException {
  .................................................
  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<Object>() {
                        @Override
                        public Object getObject() throws BeansException {
      return getEarlyBeanReference(beanName, mbd, bean);
    }
  });
}

.........................................

//开始检查循环依赖
if (earlySingletonExposure) {
  //从三级缓存中拿出刚刚实例化的bean
  Object earlySingletonReference = getSingleton(beanName, false);
  if (earlySingletonReference != null) {
    if (exposedObject == bean) {
      exposedObject = earlySingletonReference;
    }
    else if (!this.allowRawInjectionDespiteWrapping && hasDependentBean(beanName)) {
      //拿出它所有依赖的bean
      String[] dependentBeans = getDependentBeans(beanName);
      Set<String> actualDependentBeans = new LinkedHashSet<String>(dependentBeans.length);
      for (String dependentBean : dependentBeans) {
        if (!removeSingletonIfCreatedForTypeCheckOnly(dependentBean)) {
          actualDependentBeans.add(dependentBean);
        }
      }
      //如果发现有依赖的bean还没有被创建就会报异常
      if (!actualDependentBeans.isEmpty()) {
        //其实看这里的注释就知道跟解决循环依赖有关
        throw new BeanCurrentlyInCreationException(beanName,
                                                   "Bean with name '" + beanName + "' has been injected into other beans [" +
                                                   StringUtils.collectionToCommaDelimitedString(actualDependentBeans) +
                                                   "] in its raw version as part of a circular reference, but has eventually been " +
                                                   "wrapped. This means that said other beans do not use the final version of the " +
                                                   "bean. This is often the result of over-eager type matching - consider using " +
                                                   "'getBeanNamesOfType' with the 'allowEagerInit' flag turned off, for example.");
      }
    }
  }
}
..............................................
}
           

看完上面代码你是不是感觉很奇怪,上面代码只有检查依赖关系,那哪里设置依赖关系呢?下面我们从deCreateBean里进入populateBean方法中:

protected void populateBean(String beanName, RootBeanDefinition mbd, BeanWrapper bw) {
  PropertyValues pvs = mbd.getPropertyValues();
  ................
  //对属性赋值,如果属性是注入的对象,则会触发设置依赖关系
  applyPropertyValues(beanName, mbd, bw, pvs);
}
           
protected void applyPropertyValues(String beanName, BeanDefinition mbd, BeanWrapper bw, PropertyValues pvs) {
  if (pvs == null || pvs.isEmpty()) {
    return;
  }
  ..................
  //解析属性值,如果属性是依赖注入
  Object resolvedValue = valueResolver.resolveValueIfNecessary(pv, originalValue);
  ................
           

开始解析引用

public Object resolveValueIfNecessary(Object argName, Object value) {
  // We must check each value to see whether it requires a runtime reference
  // to another bean to be resolved.
  //通过xml注入的
  if (value instanceof RuntimeBeanReference) {
    RuntimeBeanReference ref = (RuntimeBeanReference) value;
    //
    return resolveReference(argName, ref);
  }
  //通过autowired注入的
  else if (value instanceof RuntimeBeanNameReference) {
    String refName = ((RuntimeBeanNameReference) value).getBeanName();
    refName = String.valueOf(doEvaluate(refName));
    if (!this.beanFactory.containsBean(refName)) {
      throw new BeanDefinitionStoreException(
        "Invalid bean name '" + refName + "' in bean reference for " + argName);
    }
    return refName;
  }
  ................................
           
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 {
      //调用getBean来创建所依赖的bean
      Object bean = this.beanFactory.getBean(refName);
      this.beanFactory.registerDependentBean(refName, this.beanName);
      return bean;
    }
  }
  .....................
           

从上面的代码我们可以看出,createBean前会先检查它所依赖的bean,如果该bean还没有被创建就调用getBean来创建该bean,这个时候就会有一个问题了,如果两个bean相互依赖,那岂不是会死循环了?

我们来继续看看解决循环依赖死循环的关键:getSingleton方法

protected Object getSingleton(String beanName, boolean allowEarlyReference) {
  //先在一级缓存中找
  Object singletonObject = this.singletonObjects.get(beanName);
  //如果发现bean还在创建中
  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还在三级缓存也会拿出来,这样它就不会重复执行doCreateBean了。

简化以上逻辑如下:

  1. 假设A与B相互依赖
  2. 创建A时先实例化放入三级缓存
  3. 赋值时发现依赖B,调用getBean方法来创建B
  4. B实例化后放入三级缓存
  5. 赋值时发现依赖A,调用getBean方法来创建A
  6. 这个时候A已经存在于第三缓存了,返回A给B
  7. 然后完成B的创建
  8. 接着完成A的创建。

关注个人微信公众号:肌肉码农,回复“好友”讨论问题。

继续阅读