本文已收录于【Spring源码札记专栏】。
关联文章:
(一)Spring IoC源码-2.bean的加载-01整体概览
(一)Spring IoC源码-2.bean的加载-02从缓存中获取单例bean
(一)Spring IoC源码-2.bean的加载-03从bean实例中获取对象
(一)Spring IoC源码-2.bean的加载-04创建bean
从缓存中获取单例bean是通过DefaultSingletonBeanRegistry.getSingleton(String)实现的。
@Override
public Object getSingleton(String beanName) {
return getSingleton(beanName, true);
}
@Nullable
protected Object getSingleton(String beanName, boolean allowEarlyReference) {
//首先从singletonObjects中获取
Object singletonObject = this.singletonObjects.get(beanName);
//如果没有获取到,且bean正在创建过程中(isSingletonCurrentlyInCreation()为true),则尝试从singletonFactories中获取
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在同一个Spring容器中只创建一次,获取bean的时候,尝试从缓存加载bean。首先从singletonObjects中获取,如果没有获取到,且bean正在创建过程中(isSingletonCurrentlyInCreation()为true),则尝试从earlySingletonObjects中获取,如果还获取不到,就求助于singletonFactories。因为spring创建单例bean的时候,存在循环依赖的问题。比如创建bean a的时候发现bean a引用了bean b,此时会去创建bean b,但又发现bean b引用了bean c,所以此时会去创建bean c,在创建bean c的过程中发现bean c引用bean a。为了避免循环依赖,Spring采取了一种将正在创建的bean实例提早暴露加入到singletonFactories缓存中,一旦下一个bean创建的时候需要依赖上个bean,则直接使用singletonFactories来获取bean。
/** Cache of singleton objects: bean name --> bean instance */
private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256);
/** Cache of singleton factories: bean name --> ObjectFactory */
private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<>(16);
/** Cache of early singleton objects: bean name --> bean instance */
private final Map<String, Object> earlySingletonObjects = new HashMap<>(16);
/** Set of registered singletons, containing the bean names in registration order */
private final Set<String> registeredSingletons = new LinkedHashSet<>(256);
提前暴露bean实例到缓存的时机是在bean实例创建(调用构造方法)之后,初始化bean实例(属性注入)之前。具体在AbstractAutowireCapableBeanFactory类的protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final Object[] args) {...}
方法中。在该方法中调用了DefaultSingletonBeanRegistry类的addSingletonFactory方法提前暴露bean实例到缓存。
protected void addSingletonFactory(String beanName, ObjectFactory<?> singletonFactory) {
Assert.notNull(singletonFactory, "Singleton factory must not be null");
synchronized (this.singletonObjects) {
if (!this.singletonObjects.containsKey(beanName)) {
this.singletonFactories.put(beanName, singletonFactory);
this.earlySingletonObjects.remove(beanName);
this.registeredSingletons.add(beanName);
}
}
}