从这篇博客开始我们开始加载bean的第一个步骤,从缓存中获取bean,代码片段如下:
1 | Object sharedInstance = getSingleton(beanName); |
首先调用getSingleton()
从缓存中获取单例bean,在上篇博客提到过,Spring对单例模式的bean只会创建一次,后续如果再获取该bean则是直接从单例缓存中获取,该过程就体现在getSingleton()
中。如下:
1 | public Object getSingleton(String beanName) { |
首先解释上面用到的一些变量:
- singletonObjects :存放的是单例bean,已经完整实例化的bean,对应关系为
bean name --> bean instance
- earlySingletonObjects:存放的是早期的bean,对应关系也是
bean name --> bean instance
。它与singletonObjects区别在于earlySingletonObjects中存放的bean不一定是完整的,从上面过程中我们可以了解,bean在创建过程中就已经加入到earlySingletonObjects中了,所以当在bean的创建过程中就可以通过getBean()
方法获取。这个Map也是解决循环依赖的关键所在。 - singletonFactories:存放的是 ObjectFactory,可以理解为创建单例bean的factory,对应关系是
bean name --> ObjectFactory
。在代码注释中也说了,这个和前面的earlySingletonObjects是互斥的。 - registeredSingletons:这个是用于保存所有已经注册的bean,这里先提前讲,后面会用到
这里先总结一下上面的整个流程
- 如果从singletonObjects中获取到的bean不为空,则进入最后一步,
- 如果获取到的bean为空,并且正在进行创建,则进入下一步,否则直接进入最后一步。
- 先锁住singletonObjects,防止其他线程插入同一个bean的不同对象,然后从earlySingletonObjects获取对应的bean,如果不为空则进入最后一步。否则进入下一步
- 如果从earlySingletonObjects获取到的对象为空,并且允许提前暴露bean对象,则从singletonFactories获取对应的创建bean的工厂,如果不为空,则创建bean对象,并将此插入到earlySingletonObjects中,然后从singletonFactories移除。
- 返回singletonObject对象。
下面我们来看看上面存放键值对的Map种类,代码如下
1 | /** |
从上面可以看出,singletonObjects为了确保线程安全,使用的是ConcurrentHashMap。其他的是通过Synchronized关键字来保证的线程安全。
在上面代码中还有一个非常重要的检测方法 isSingletonCurrentlyInCreation(beanName)
,该方法用于判断该beanName对应的bean是否在创建过程中,注意这个过程讲的是整个IOC中。如下:
1 | public boolean isSingletonCurrentlyInCreation(String beanName) { |
从这段代码中我们可以预测,在bean创建过程中会将其加入到singletonsCurrentlyInCreation集合中,具体是在什么时候加的,我们后面分析。
到这里从缓存中获取bean的过程已经分析完毕了,我们再看开篇的代码段,从缓存中获取bean后,若其不为null且args为空,则会调用 getObjectForBeanInstance()
处理。
为什么会有这么一段呢?因为我们从缓存中获取的bean是最原始的bean并不一定使我们最终想要的bean,所以需要调用getObjectForBeanInstance()
进行处理,该方法的定义为获取给定bean实例的对象,该对象要么是bean实例本身,要么就是FactoryBean创建的对象,如下:
1 | protected Object getObjectForBeanInstance(Object beanInstance, String name, String beanName, { RootBeanDefinition mbd) |
该方法主要是进行检测工作的,主要如下:
根据name判断获取的bean实例是否为FactoryBean(以 & 开头),如果是,会进行如下检测
- 检测beanInstance是否为NullBean 类型,这个是spring定义的null类型,如果是则直接返回,
- 如果beanInstance不是FactoryBean类型则抛出 BeanIsNotFactoryException 异常。
这里主要是校验 beanInstance 的正确性。
判断当前beanInstance不是FactoryBean,如果不是则直接返回,如果是则判断用户是否希望获取的是FactoryBean类型的bean。如果是直接返回。这里有一点需要主要的是,FactoryBean创建的bean会单独存放在factoryBeanObjectCache,不会存放在singletonObjects中。
从factoryBeanObjectCache中获取对应的bean,如果获取到的对象不为空,则返回
如果获取到的对象为空,则需要委托getObjectFromFactoryBean来进一步处理。
再继续分析getObjectFromFactoryBean
之前,我们先介绍一下FactoryBean,感觉很相似,因为我们前面经常说BeanFactory,简单说一下他们的区别。 BeanFactory和FactoryBean其实没有什么比较性的,只是两者的名称特别接近,所以有时候会拿出来比较一番,BeanFactory是提供了IOC容器最基本的形式,给具体的IOC容器的实现提供了规范,FactoryBean可以说为IOC容器中Bean的实现提供了更加灵活的方式,FactoryBean在IOC容器的基础上给Bean的实现加上了一个简单工厂模式和装饰模式,我们可以在getObject()方法中灵活配置。具体的可以看这篇文章BeanFactory和FactoryBean的区别
从上面可以看出 getObjectForBeanInstance()
主要是返回给定的bean实例对象,当然该实例对象为非FactoryBean类型,对于FactoryBean类型的bean,则是委托getObjectFromFactoryBean()
从FactoryBean获取bean实例对象。
1 | protected Object getObjectFromFactoryBean(FactoryBean<?> factory, |
主要分为俩种情况,一种是FactoryBean为单例,另一种不是单例
先说第一种情况,FactoryBean为单例
为了线程安全,获取同步锁(其实我们在前面篇幅中发现了大量的同步锁,锁住的对象都是this.singletonObjects,主要是因为在单例模式中必须要保证全局唯一),然后从factoryBeanObjectCache从获取beanName对应的bean。判断是否为空
不为空直接返回。
如果为空,则调用doGetObjectFromFactoryBean进行创建,如果创建之后检测到factoryBeanObjectCache已经有,则抛弃当前的bean。如果没有,则需要对当前创建的bean进行后续处理。
如果需要后续处理,则进行进一步处理,步骤如下:
- 若该 bean 处于创建中(isSingletonCurrentlyInCreation),则返回非处理对象,而不是存储它。这个是因为后面即将讲到的循环依赖所以你的,由于bean之间的依赖,会造成一些bean还没有初始化完成就提前创建出该对象的ObjectFactory对象,然后来生成对应bean,让正在创建的bean创建能继续处理,这里先理解个大概,后面会仔细说。
- 调用
beforeSingletonCreation()
进行创建之前的处理。默认实现将该 bean 标志为当前创建的。 - 调用
postProcessObjectFromFactoryBean()
对从 FactoryBean 获取的 bean 实例对象进行后置处理,默认实现是按照原样直接返回,具体实现是在 AbstractAutowireCapableBeanFactory 中实现的,当然子类也可以重写它,比如应用后置处理 - 调用
afterSingletonCreation()
进行创建 bean 之后的处理,默认实现是将该 bean 标记为不再在创建中。 - 最后加入到 FactoryBeans 缓存中。
第二种情况,不是单例
- 根据传进来的factory创建出对应的bean实例
- 进行后置处理,然后返回
该方法应该就是创建 bean 实例对象中的核心方法之一了。方法doGetObjectFromFactoryBean
内部就是调用FactoryBean.get返回对应的bean,比较简单所以就不仔细说明。这里我们关注三个方法:beforeSingletonCreation()
、afterSingletonCreation()
、postProcessObjectFromFactoryBean()
。可能有小伙伴觉得前面两个方法不是很重要,可以肯定告诉你,这两方法是非常重要的操作,因为他们记录着bean的加载状态,是检测当前bean是否处于创建中的关键之处,对解决bean循环依赖起着关键作用。before方法用于标志当前bean处于创建中,after则是移除。其实在这篇博客刚刚开始就已经提到了 isSingletonCurrentlyInCreation()
是用于检测当前 bean 是否处于创建之中,如下:
1 | public boolean isSingletonCurrentlyInCreation(String beanName) { |
是根据 singletonsCurrentlyInCreation 集合中是否包含了 beanName,集合的元素则一定是在 beforeSingletonCreation()
中添加的,如下:
1 | protected void beforeSingletonCreation(String beanName) { |
afterSingletonCreation()
为移除,则一定就是对 singletonsCurrentlyInCreation 集合 remove 了,如下:
1 | protected void afterSingletonCreation(String beanName) { |
postProcessObjectFromFactoryBean()
是对从FactoryBean处获取的bean实例对象进行后置处理,其默认实现是直接返回object对象,不做任何处理,子类可以重写,例如应用后处理器。AbstractAutowireCapableBeanFactory 对其提供了实现,如下:
1 | protected Object postProcessObjectFromFactoryBean(Object object, String beanName) { |
该方法的定义为:对所有的postProcessAfterInitialization进行回调注册BeanPostProcessors,让他们能够后期处理从 FactoryBean 中获取的对象。下面是具体实现:
1 | public Object applyBeanPostProcessorsAfterInitialization(Object existingBean, |
对于后置处理器,这里我们不做过多阐述,后面会专门的博文进行详细介绍,这里我们只需要记住一点:尽可能保证所有bean初始化后都会调用注册的 BeanPostProcessor.postProcessAfterInitialization()
方法进行处理,在实际开发过程中大可以针对此特性设计自己的业务逻辑。