5.2 缓存中获取单例bean
介绍过FactoryBean的用法后,我们就可以了解bean加载的过程了。前面已经提到过,单例在Spring的同一个容器内只会被创建一次,后续再获取bean直接从单例缓存中获取,当然这里也只是尝试加载,首先尝试从缓存中加载,然后再次尝试尝试从singletonFactories中加载。因为在创建单例bean的时候会存在依赖注入的情况,而在创建依赖的时候为了避免循环依赖,Spring创建bean的原则是不等bean创建完成就会将创建bean的ObjectFactory提早曝光加入到缓存中,一旦下一个bean创建时需要依赖上
1 public Object getSingleton(String beanName) { 2 //参数true设置标识允许早期依赖 3 return getSingleton(beanName, true); 4 } 5 6 protected Object getSingleton(String beanName, boolean allowEarlyReference) { 7 //检查缓存中是否存在实例 8 Object singletonObject = this.singletonObjects.get(beanName); 9 if (singletonObject == null) { 10 //如果为空,则锁定全局变量并进行处理 11 synchronized (this.singletonObjects) { 12 //如果此bean正在加载则不处理 13 singletonObject = this.earlySingletonObjects.get(beanName); 14 if (singletonObject == null && allowEarlyReference) { 15 //当某些方法需要提前初始化的时候则会调用addSingletonFactory方法将对应的ObjectFactory初始化策略存储在singletonFactories 16 ObjectFactory singletonFactory = this.singletonFactories.get (beanName); 17 if (singletonFactory != null) { 18 //调用预先设定的getObject方法 19 singletonObject = singletonFactory.getObject(); 20 //记录在缓存中,earlySingletonObjects和singletonFactories互斥 21 this.earlySingletonObjects.put(beanName, singletonObject); 22 this.singletonFactories.remove(beanName); 23 } 24 } 25 } 26 } 27 return (singletonObject != NULL_OBJECT ? singletonObject : null); 28 }
这个方法因为涉及循环依赖的检测,以及涉及很多变量的记录存取,所以让很多读者摸不着头脑。这个方法首先尝试从singletonObjects里面获取实例,如果获取不到再从earlySingleton Objects里面获取,如果还获取不到,再尝试从singletonFactories里面获取beanName对应的ObjectFactory,然后调用这个ObjectFactory的getObject来创建bean,并放到earlySingleton Objects里面去,并且从singletonFacotories里面remove掉这个ObjectFactory,而对于后续的所有内存操作都只为了循环依赖检测时候使用,也就是在allowEarlyReference为true的情况下才会使用。
这里涉及用于存储bean的不同的map,可能让读者感到崩溃,简单解释如下。
singletonObjects:用于保存BeanName和创建bean实例之间的关系,bean name --> bean instance。
singletonFactories:用于保存BeanName和创建bean的工厂之间的关系,bean name --> ObjectFactory。
earlySingletonObjects:也是保存BeanName和创建bean实例之间的关系,与singletonObjects的不同之处在于,当一个单例bean被放到这里面后,那么当bean还在创建过程中,就可以通过getBean方法获取到了,其目的是用来检测循环引用。
registeredSingletons:用来保存当前所有已注册的bean。