Spring5源码分析(023)——IoC篇之bean加载:从缓存中获取单例 bean
注:《Spring5源码分析》汇总可参考:Spring5源码分析(002)——博客汇总
/// org.springframework.beans.factory.support.AbstractBeanFactory // Eagerly check singleton cache for manually registered singletons. /* * 2、从缓存或者实例工厂中获取单例 bean 对象:检查缓存中或者实例工厂中是否有对应的 bean 实例 * 为什么需要使用这段代码,来检查缓存? * 因为在创建单例 bean 的时候会存在依赖注入的情况,而在创建依赖的时候为了避免依赖循环, * Spring 创建 bean 的原则是不等 bean 创建完成就会将创建 bean 的 ObjectFactory 提前曝光, * 也就是将 ObjectFactory 加入到缓存中,一旦下个 bean 创建时需要依赖上个 bean 则直接使用 ObjectFactory */ // 检查注册的单例缓存中是否有对应的单例 Object sharedInstance = getSingleton(beanName); if (sharedInstance != null && args == null) { if (logger.isTraceEnabled()) { if (isSingletonCurrentlyInCreation(beanName)) { logger.trace("Returning eagerly cached instance of singleton bean '" + beanName + "' that is not fully initialized yet - a consequence of a circular reference"); } else { logger.trace("Returning cached instance of singleton bean '" + beanName + "'"); } } // 返回对应的实例,有时候存在诸如 FactoryBean 的情况下,可能返回 FactoryBean 本身, // 也有可能返回的是 FactoryBean 指定方法返回的实例 bean = getObjectForBeanInstance(sharedInstance, name, beanName, null); }
本文目录结构如下:
1、getSingleton
/// org.springframework.beans.factory.support.DefaultSingletonBeanRegistry @Override @Nullable public Object getSingleton(String beanName) { // 参数 allowEarlyReference 标识设置为 true 表示允许提前依赖引用 return getSingleton(beanName, true); } /** * Return the (raw) singleton object registered under the given name. * <p>Checks already instantiated singletons and also allows for an early * reference to a currently created singleton (resolving a circular reference). * <p>返回在给定名称下注册的(原始)单例对象 * <p>检查已实例化的单例,并允许提前引用当前正在创建中的单例(解析循环引用)。 * @param beanName the name of the bean to look for * @param allowEarlyReference whether early references should be created or not * @return the registered singleton object, or {@code null} if none found */ @Nullable protected Object getSingleton(String beanName, boolean allowEarlyReference) { // 检查单例缓存中是否存在实例 Object singletonObject = this.singletonObjects.get(beanName); // 如果为空,并且该 bean 正在创建中 if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) { // 加锁,锁住 singletonObjects 全局变量并进行处理 synchronized (this.singletonObjects) { // 从 earlySingletonObjects 中获取 // 如果该 bean 正在加载则不处理 // 因为单例 singleton 是复用以前的创建的 bean ,因此需要检查是否已创建或者创建中 singletonObject = this.earlySingletonObjects.get(beanName); // 只有 earlySingletonObjects 中不存在且允许提前创建,才会进行 singleton bean 的实例化 if (singletonObject == null && allowEarlyReference) { // 从 singletonFactories 中获取对应的 ObjectFactory // 当某些方法需要提前初始化的时候会调用 addSingletonFactory 方法将对应的 // ObjectFactory 初始化策略存储在 singletonFactories 中 ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName); if (singletonFactory != null) { // 调用预先设定的 getObject 方法获得 bean singletonObject = singletonFactory.getObject(); // 记录在缓存中, earlySingletonObjects 和 singletonFactories 互斥 // 添加 bean 到 earlySingletonObjects 中 this.earlySingletonObjects.put(beanName, singletonObject); // 从 singletonFactories 移除对应的 ObjectFactory this.singletonFactories.remove(beanName); } } } } return singletonObject; }
- 第一步,首先尝试从单例缓存 singletonObjects 里面获取 bean 实例对象。
- 第二步,如果获取不到,则再从 earlySingletonObjects 里面获取。
- 第三步,如果还获取不到,且允许提前创建,则尝试从 singletonFactories 里面获取 beanName 对应的 ObjectFactory ,若不为空则调用 ObjectFactory#getObject() 来创建 bean ,然后放到 earlySingletonObjects 里面去,并且从 singletonFactories 里面删除掉 ,而对于后续的所有内存操作都只为了循环依赖检测时候使用,也就是在 allowEarlyReference 为 true 的情况下才会使用。
/// org.springframework.beans.factory.support.DefaultSingletonBeanRegistry /** * Cache of singleton objects: bean name to bean instance. * <p>单例 bean 实例对象的缓存映射: beanName --> bean 实例。 * <p>保存实例化、初始化都完成的单例 bean 对象,称为【一级缓存】 */ private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256); /** * Cache of singleton factories: bean name to ObjectFactory. * <p>单例 Factory 缓存(创建 bean 的工厂)映射: beanName --> ObjectFactory。 * <p>保存对象工厂 ObjectFactory ,用于创建二级缓存中的对象,称为【三级缓存】 */ private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<>(16); /** * Cache of early singleton objects: bean name to bean instance. * <p>单例 bean 实例对象的缓存: beanName --> bean 实例。 * <p>保存实例化完成、但是未初始化完成的提前曝光的对象,即早期的 bean ,称为【二级缓存】 * <p>与 {@link #singletonObjects }的区别在于其存放的 bean 不一定是完整的, * 而从{@link #getSingleton(String) }中可以看到 bean 创建过程中就直接加入到 earlySingletonObjects * 中了,所以才可以通过 getBean 获取创建过程中的 bean ,这也是解决【循环依赖】 的关键所在 */ private final Map<String, Object> earlySingletonObjects = new HashMap<>(16);
1.1、isSingletonCurrentlyInCreation(String beanName)
/// org.springframework.beans.factory.support.DefaultSingletonBeanRegistry /** * Names of beans that are currently in creation. * <p>当前正在创建中的 beans 的 beanName 集合 */ private final Set<String> singletonsCurrentlyInCreation = Collections.newSetFromMap(new ConcurrentHashMap<>(16)); /** * Return whether the specified singleton bean is currently in creation * (within the entire factory). * <p>返回指定的单例bean当前是否正在创建(在整个 beanFactory 内)。 * @param beanName the name of the bean */ public boolean isSingletonCurrentlyInCreation(String beanName) { return this.singletonsCurrentlyInCreation.contains(beanName); }
结合前面提到的,首先需要获取是否有已经实例化完整的 bean ,如果没有而且允许提前创建,这个时候才会去查找创建过程中的 bean 。因此可以猜到,bean 创建过程中都会加入到 singletonsCurrentlyInCreation 集合中,这样就知道哪些在创建中可以提前返回引用了,否则就很难判断实例化过程中的循环依赖了。至于创建过程中是在哪里、什么时候加的,后面会分析到。(注:后面 DefaultSingletonBeanRegistry#getSingleton(String beanName, ObjectFactory<?> singletonFactory) 中的创建前的前置处理中默认会用到)
2、getObjectForBeanInstance
/** * Get the object for the given bean instance, either the bean * instance itself or its created object in case of a FactoryBean. * <p>获取给定Bean实例的对象,如果是 FactoryBean ,则获取Bean实例本身或其创建的对象。 * @param beanInstance the shared bean instance * @param name name that may include factory dereference prefix * @param beanName the canonical bean name * @param mbd the merged bean definition * @return the object to expose for the bean */ protected Object getObjectForBeanInstance( Object beanInstance, String name, String beanName, @Nullable RootBeanDefinition mbd) { // Don't let calling code try to dereference the factory if the bean isn't a factory. // 1、如果指定的 name 是工厂类相关,即 & 前缀 if (BeanFactoryUtils.isFactoryDereference(name)) { // 如果是 NullBean 类型则直接返回 if (beanInstance instanceof NullBean) { return beanInstance; } // beanInstance 不是 FactoryBean 类型则验证不通过,抛出异常 if (!(beanInstance instanceof FactoryBean)) { throw new BeanIsNotAFactoryException(beanName, beanInstance.getClass()); } // 设置 isFactoryBean 标识为 true if (mbd != null) { mbd.isFactoryBean = true; } // 返回工厂 bean 本身 return beanInstance; } // Now we have the bean instance, which may be a normal bean or a FactoryBean. // If it's a FactoryBean, we use it to create a bean instance, unless the // caller actually wants a reference to the factory. // 到这里我们已经有了一个 bean 实例,该实例可能是普通的 bean 或者是 FactoryBean, // 如果是 FactoryBean ,我们需要使用它来创建 bean 实例 ,除非是需要 FactoryBean 本身 // 2、非 FactoryBean 的普通 bean ,直接返回 if (!(beanInstance instanceof FactoryBean)) { return beanInstance; } Object object = null; if (mbd != null) { mbd.isFactoryBean = true; } else { // 3、如果 RootBeanDefinition 为 null,则尝试从 factoryBeanObjectCache 缓存中加载 bean object = getCachedObjectForFactoryBean(beanName); } // 若 object 依然为空,而到这里可以确认 beanInstance 一定是 FactoryBean 类型,则使用 FactoryBean 来创建 bean if (object == null) { // Return bean instance from factory. FactoryBean<?> factory = (FactoryBean<?>) beanInstance; // 检测 beanDefinitionMap 中也就是在所有已经加载的类中检测是否定义 beanName // Caches object obtained from FactoryBean if it is a singleton. if (mbd == null && containsBeanDefinition(beanName)) { // 将存储 XML 配置的 GenericBeanDefinition 转换成 RootBeanDefinition , // 如果指定的 beanName 是子bean的话同时会合并父类的相关属性 mbd = getMergedLocalBeanDefinition(beanName); } // 是否是用户定义的而不是应用程序本身定义的 boolean synthetic = (mbd != null && mbd.isSynthetic()); // 使用 FactoryBean 获得 Bean 实例对象 object = getObjectFromFactoryBean(factory, beanName, !synthetic); } return object; }
这个方法主要做了如下处理:
- 1、校验 beanInstance 的正确性:如果指定的 name 是工厂类相关的( & 前缀)且 beanInstance 是 NullBean 类型则直接返回;如果 beanInstance 不是 FactoryBean 类型则抛出 BeanIsNotAFactoryException 异常;是 FactoryBean 则直接返回了。这个是需要返回 FactoryBean 本身的场景,后面则是需要返回 bean 实例。
- 2、如果 beanInstance 不是 FactoryBean 类型,则直接返回该实例。
- 3、如果 BeanDefinition 为空(前面调用传的就是空),则从 factoryBeanObjectCache 缓存中获取 bean 实例对象,如果还是为空,我们知道此时 beanInstance 肯定已经是 FactoryBean 类型,需要处理的就是通过 FactoryBean 来获得对应的 bean 实例,这里是通过委托 FactoryBeanRegistrySupport#getObjectFromFactoryBean(FactoryBean<?> factory, String beanName, boolean shouldPostProcess) 方法来处理,可以猜想到的是,里面会调用 #getObject() 方法,获得最终自定义的 bean 实例。
- 第1种是非 FactoryBean 类型,直接返回 bean 实例对象 beanInstance
- 第2种就是 FactoryBean 类型,当然,如果确实是需要返回工厂类本身,这里直接就返回了 beanInstance ;如果不是,则是通过 FactoryBean 来获取实际的 bean 实例对象,也就是 #getObjectFromFactoryBean(...) 方法所作的事情。
2.1、getObjectFromFactoryBean
/** * Obtain an object to expose from the given FactoryBean. * <p>从给定的 FactoryBean 中获取对象实例 * @param factory the FactoryBean instance * @param beanName the name of the bean * @param shouldPostProcess whether the bean is subject to post-processing * @return the object obtained from the FactoryBean * @throws BeanCreationException if FactoryBean object creation failed * @see org.springframework.beans.factory.FactoryBean#getObject() */ protected Object getObjectFromFactoryBean(FactoryBean<?> factory, String beanName, boolean shouldPostProcess) { // 1、如果是单例模式且缓存中存在 if (factory.isSingleton() && containsSingleton(beanName)) { // 1.1、对单例缓存加锁 synchronized (getSingletonMutex()) { // 1.2、从缓存中获取指定的 bean 实例 Object object = this.factoryBeanObjectCache.get(beanName); if (object == null) { // 1.3、缓存中没有,则通过 FactoryBean 获取 bean 实例 object = doGetObjectFromFactoryBean(factory, beanName); // 从缓存中获取,如果缓存中已经存在,则使用缓存中的实例 // Only post-process and store if not put there already during getObject() call above // (e.g. because of circular reference processing triggered by custom getBean calls) Object alreadyThere = this.factoryBeanObjectCache.get(beanName); if (alreadyThere != null) { object = alreadyThere; } else { // 1.4、需要后续处理 if (shouldPostProcess) { // 如果 bean 实例还在创建中,则直接返回该对象实例 if (isSingletonCurrentlyInCreation(beanName)) { // Temporarily return non-post-processed object, not storing it yet.. return object; } // 单例 bean 的创建前处理 beforeSingletonCreation(beanName); try { // 对从 FactoryBean 获取的实例进行后处理,主要是后处理器 BeanPostProcessor 处理 object = postProcessObjectFromFactoryBean(object, beanName); } catch (Throwable ex) { throw new BeanCreationException(beanName, "Post-processing of FactoryBean's singleton object failed", ex); } finally { // 单例 bean 创建完后置处理 afterSingletonCreation(beanName); } } // 1.5、添加到 factoryBeanObjectCache 缓存中 if (containsSingleton(beanName)) { this.factoryBeanObjectCache.put(beanName, object); } } } return object; } } else { // 2、不是单例模式,则从 FactoryBean 中获取 Object object = doGetObjectFromFactoryBean(factory, beanName); // 2.1、需要后续处理 if (shouldPostProcess) { try { // 对从 FactoryBean 获取的实例进行后处理,主要是后处理器 BeanPostProcessor 处理 object = postProcessObjectFromFactoryBean(object, beanName); } catch (Throwable ex) { throw new BeanCreationException(beanName, "Post-processing of FactoryBean's object failed", ex); } } return object; } }
- 1、如果 FactoryBean 是单例模式且【一级缓存】 singletonObjects 中存在相关的 beanName ,则进行后续处理,否则按照非单例模式处理(第2步)
- 1.1、首先,就是获取单例缓存 singletonObjects 的锁。可以发现,前面很多解析中也提到了 singletonObjects 的对象锁,这里是为了保证单例实例在单例模式中的唯一性,代码如下:
/// org.springframework.beans.factory.support.DefaultSingletonBeanRegistry /** * Cache of singleton objects: bean name to bean instance. * <p>单例 bean 实例对象的缓存映射: beanName --> bean 实例。 * <p>保存实例化、初始化都完成的单例 bean 对象,称为【一级缓存】 */ private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256); @Override public final Object getSingletonMutex() { return this.singletonObjects; }
-
- 1.2、其次,从缓存 factoryBeanObjectCache 中获取 bean 实例。如果存在,说明之前已经处理过,直接返回。
- 1.3、如果不存在,则调用 #doGetObjectFromFactoryBean(final FactoryBean<?> factory, final String beanName) 方法,从 FactoryBean 获取实例对象,内部其实就是调用了我们一直提到的 FactoryBean#getObject() 方法,代码如下,中间可以看到,确实是调用了 #getObject() 来获取实例对象:
/// org.springframework.beans.factory.support.FactoryBeanRegistrySupport /** * Obtain an object to expose from the given FactoryBean. * <p>从给定的 FactoryBean 中获取对象实例 * @param factory the FactoryBean instance * @param beanName the name of the bean * @return the object obtained from the FactoryBean * @throws BeanCreationException if FactoryBean object creation failed * @see org.springframework.beans.factory.FactoryBean#getObject() */ private Object doGetObjectFromFactoryBean(final FactoryBean<?> factory, final String beanName) throws BeanCreationException { Object object; try { // 权限验证 if (System.getSecurityManager() != null) { AccessControlContext acc = getAccessControlContext(); try { object = AccessController.doPrivileged((PrivilegedExceptionAction<Object>) factory::getObject, acc); } catch (PrivilegedActionException pae) { throw pae.getException(); } } else { // 直接调用 getObject 方法获取 bean 实例 object = factory.getObject(); } } catch (FactoryBeanNotInitializedException ex) { throw new BeanCurrentlyInCreationException(beanName, ex.toString()); } catch (Throwable ex) { throw new BeanCreationException(beanName, "FactoryBean threw exception on object creation", ex); } // Do not accept a null value for a FactoryBean that's not fully // initialized yet: Many FactoryBeans just return null then. if (object == null) { // 如果当前 bean 正在创建中,则抛出异常 if (isSingletonCurrentlyInCreation(beanName)) { throw new BeanCurrentlyInCreationException( beanName, "FactoryBean which is currently in creation returned null from getObject"); } // getObject 返回 null 则是统一使用 NullBean object = new NullBean(); } return object; }
- 1.4、如果需要对新创建的 bean 实例进行后续处理,则
- 如果该 bean 实例对象还在创建中,即 DefaultSingletonBeanRegistry#isSingletonCurrentlyInCreation(String beanName) 方法返回 true ,则直接返回该对象,无需进一步处理。
- 调用 #beforeSingletonCreation(String beanName) 方法,进行创建之前的处理,默认实现是将该 bean 注册为正在创建中。
- 调用 #postProcessObjectFromFactoryBean(Object object, String beanName) 对从 FactoryBean 获取的实例进行后处理,主要扩展是后处理器 BeanPostProcessor 处理。
- 调用 #afterSingletonCreation(String beanName) 方法,进行 bean 对象实例创建完后处理,默认实现是将该 bean 标记为不在创建中,也即是从正在创建中移除。
- 1.5、将获得的 bean 对象添加到 1.2 中提到 factoryBeanObjectCache 中,以便下次获取该单例。
- 2、此时已经知道是非单例模式,则直接调用 #doGetObjectFromFactoryBean(final FactoryBean<?> factory, final String beanName) 方法,从 FactoryBean 获取实例对象,当然,这里如果需要后续处理的话,只需要调用 #postProcessObjectFromFactoryBean(Object object, String beanName) 对从 FactoryBean 获取的实例进行后处理,因为非单例模式并不需要标记状态,而是直接使用。
- #isSingletonCurrentlyInCreation(String beanName)
- #beforeSingletonCreation(String beanName)
- #postProcessObjectFromFactoryBean(Object object, String beanName)
- #afterSingletonCreation(String beanName)
2.2、isSingletonCurrentlyInCreation
- #beforeSingletonCreation(String beanName):创建 bean 前调用,将该 beanName 标记为正在创建中;
- #afterSingletonCreation(String beanName):创建 bean 后调用,将该 beanName 移除正在创建中的标记。
/// org.springframework.beans.factory.support.DefaultSingletonBeanRegistry /** * Names of beans that are currently in creation. * <p>当前正在创建中的 beans 的 beanName 集合 */ private final Set<String> singletonsCurrentlyInCreation = Collections.newSetFromMap(new ConcurrentHashMap<>(16)); /** * Return whether the specified singleton bean is currently in creation * (within the entire factory). * <p>返回指定的单例bean当前是否正在创建(在整个 beanFactory 内)。 * @param beanName the name of the bean */ public boolean isSingletonCurrentlyInCreation(String beanName) { return this.singletonsCurrentlyInCreation.contains(beanName); }
2.3、beforeSingletonCreation
/// org.springframework.beans.factory.support.DefaultSingletonBeanRegistry /** * Callback before singleton creation. * <p>The default implementation register the singleton as currently in creation. * <p>单例创建前回调,默认实现是将单例注册为正在创建中 * @param beanName the name of the singleton about to be created * @see #isSingletonCurrentlyInCreation */ protected void beforeSingletonCreation(String beanName) { if (!this.inCreationCheckExclusions.contains(beanName) && !this.singletonsCurrentlyInCreation.add(beanName)) { throw new BeanCurrentlyInCreationException(beanName); } }
2.4、afterSingletonCreation
在单例创建后从 singletonsCurrentlyInCreation 中移除标志,表示不再处于创建中状态,代码如下:
/// org.springframework.beans.factory.support.DefaultSingletonBeanRegistry /** * Callback after singleton creation. * <p>The default implementation marks the singleton as not in creation anymore. * <p>单例创建后回调,默认实现是标记单例不在创建中,即从正在创建中移除 * @param beanName the name of the singleton that has been created * @see #isSingletonCurrentlyInCreation */ protected void afterSingletonCreation(String beanName) { if (!this.inCreationCheckExclusions.contains(beanName) && !this.singletonsCurrentlyInCreation.remove(beanName)) { throw new IllegalStateException("Singleton '" + beanName + "' isn't currently in creation"); } }
2.5、postProcessObjectFromFactoryBean
FactoryBeanRegistrySupport#postProcessObjectFromFactoryBean(Object object, String beanName) 方法主要是扩展进行后置处理,org.springframework.beans.factory.support.FactoryBeanRegistrySupport 中默认是空实现不进行处理,直接返回实例对象。代码如下:
/** * Post-process the given object that has been obtained from the FactoryBean. * The resulting object will get exposed for bean references. * <p>The default implementation simply returns the given object as-is. * Subclasses may override this, for example, to apply post-processors. * @param object the object obtained from the FactoryBean. * @param beanName the name of the bean * @return the object to expose * @throws org.springframework.beans.BeansException if any post-processing failed */ protected Object postProcessObjectFromFactoryBean(Object object, String beanName) throws BeansException { return object; }
注释里面提到,子类可以重写此方法,用于扩展进行进行后置处理。我们看下 Spring 中已经提供的实现: org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory 。
2.6、AbstractAutowireCapableBeanFactory
/// org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory /** * Applies the {@code postProcessAfterInitialization} callback of all * registered BeanPostProcessors, giving them a chance to post-process the * object obtained from FactoryBeans (for example, to auto-proxy them). * <p>应用所有注册的 BeanPostProcessors 的 postProcessAfterInitialization 回调, * 使它们有机会对从 FactoryBeans 获取的对象进行后处理(例如,自动代理它们)。 * @see #applyBeanPostProcessorsAfterInitialization */ @Override protected Object postProcessObjectFromFactoryBean(Object object, String beanName) { return applyBeanPostProcessorsAfterInitialization(object, beanName); } @Override public Object applyBeanPostProcessorsAfterInitialization(Object existingBean, String beanName) throws BeansException { Object result = existingBean; for (BeanPostProcessor processor : getBeanPostProcessors()) { Object current = processor.postProcessAfterInitialization(result, beanName); if (current == null) { return result; } result = current; } return result; }
可以看到, AbstractAutowireCapableBeanFactory 中的实现主要用于后处理器 BeanPostProcessor 对创建完的 bean 实例进行处理。关于后处理器的使用,本文暂且不表,后续文章将会进行详细的分析和介绍。这里,我们只需要了解在 Spring 获取 bean 的规则中有这样一条:尽可能保证所有 bean 初始化后都会调用注册的 BeanPostProcessor#postProcessAfterInitialization 方法进行处理,在实际开发过程中大可以针对此特性设计自己的业务逻辑。
3、参考
- [1]spring 官方文档 5.2.3.RELEASE:https://docs.spring.io/spring-framework/docs/5.2.3.RELEASE/spring-framework-reference/core.html
- [2]Spring源码深度解析(第2版),郝佳,P93-P98
- [3]相关注释和案例可参考笔者 github 链接:https://github.com/wpbxin/spring-framework