缓存中获取单例bean
前言
上一篇文章FactoryBean的使用实际上是为了Bean的加载的详细解析进行的介绍FactoryBean,从这篇文章开始,LZ会对Bean的加载过程进行详细的讲述,之前文章Bean的加载只是对Bean的加载过程进行了快速的大致上的过了一遍,详细的解析过程开始。。。
缓存中获取单例bean
前面的文章Bean的加载已经提到过,单例在Spring的同一个容器中只会被创建一次,后续再获取bean直接从单例缓存中获取,当然这里也只是尝试加载,首先尝试从缓存中加载,然后再尝试从singletonFactories中加载。因为在创建单例bean的时候会存在依赖注入的情况,而在创建依赖的时候为了避免循环依赖,Spring创建bean的原则是不等bean创建完成就会将创建bean的ObjectFactory提早曝光加入到缓存中,一旦下一个bean创建的时候需要依赖上个bean,则直接使用ObjectFactory。这句代码在Bean加载的源码中是(太多所以摘选):
Object sharedInstance = getSingleton(beanName);
跟踪源代码:
public Object getSingleton(String beanName) { //参数设置为true,表示允许早期依赖 return getSingleton(beanName, true); }
1 protected Object getSingleton(String beanName, boolean allowEarlyReference) { 2 //检查缓存中是否存在依赖 3 Object singletonObject = this.singletonObjects.get(beanName); 4 if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) { 5 //如果为空,则锁定全局变量并进行处理 6 synchronized (this.singletonObjects) { 7 //如果此bean正在加载则不处理 8 singletonObject = this.earlySingletonObjects.get(beanName); 9 if (singletonObject == null && allowEarlyReference) { 10 //当某些方法需要提前初始化的时候则会调用addSingletonFactory方法将对应的objectFactory初始化策略存储在singletonFactories里面 11 ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName); 12 if (singletonFactory != null) { 13 //调用预先设定的getObject方法 14 singletonObject = singletonFactory.getObject(); 15 //记录在缓存中,earlySingletonObjects和singletonFactories互斥 16 this.earlySingletonObjects.put(beanName, singletonObject); 17 //互斥,所以移除 18 this.singletonFactories.remove(beanName); 19 } 20 } 21 } 22 } 23 return singletonObject; 24 }
上述的代码因为涉及循环依赖的检测,以及涉及很多的变量的记录存取,说明一下逻辑:
(1)第3行:首先尝试从singletonObjects里面获取实例;
(2)第8行:如果从singletonObjects里面获取不到实例,则从earlySingletonObjects里面获取;
(3)第11行:如果经过上述两步还是没有获取到,则尝试从singletonFactories里面获取beanName对应的ObjectFactory;
(4)第14~18行:调用从singletonFactories里面获取到的ObjectFactory里的getObject()方法来创建bean,并将其放到earlySingletonObjects里面去,并且从singletonFactories里面的这个对象remove掉(第3、4步都是为了循环依赖检测时候使用,即allowEarlyReference为true)。
(5)第23行:返回Object。
下面对上述出现的用于存储bean的不同的map,进行一下简单的解释:
❤ singletonObjects:用于保存beanName和创建bean实例之间的关系(beanName --> bean instance);
❤ singletonFactories:用于保存beanName和创建bean的工厂之间的关系(beanName --> ObjectFactory);
❤ earlySingletonObjects:也是用于保存beanName和创建bean实例之间的关系,与singletonObjects的不同之处在于,当一个单例bean被放到earlySingletonObjects后,那么当bean还在创建的过程中,就可以通过getBean方法获取到了,其目的是用来检测循环用,同时singletonObjects和earlySingletonObjects之间互斥,即单例bean只能在earlySingletonObjects和singletonObjects之中的一个,不能两者都存在;
❤ registeredSingletons:用来保存当前所有已注册的bean;
从bean的实例中获取对象
经过上述从缓存中获取单例bean之后,源代码中bean的加载也就是getBean就会走到:
bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);
在getBean()整个方法中,getObjectForBeanInstance()方法是个高频率使用的方法,无论是从缓存中获得bean还是根据不同的scope策略加载bean。总之,我们得到bean的实例后要做的第一步就是调用这个方法来检测一下正确性,其实就是用于检测当前bean是否是FactoryBean类型的bean,如果是,那么需要调用该bean对应的FactoryBean实例中的getObject()方法作为返回值。
无论是从缓存中获取到的bean还是通过不同的scope策略加载的bean都只是最原始的bean状态,并不一定是我们最终想要的bean。举个例子:假如我们需要对工厂bean进行处理,那么这里得到的其实是工厂bean的初始状态,但是我们真正需要的是工厂bean中定义的factory-method方法中返回的bean,而getObjectForBeanInstance方法就是完成这个工作的。
跟踪源代码:
protected Object getObjectForBeanInstance( Object beanInstance, String name, String beanName, @Nullable RootBeanDefinition mbd) { //如果指定的name是工厂相关(以&为前缀)且beanInstance又不是FactoryBean类型则验证不通过 if (BeanFactoryUtils.isFactoryDereference(name)) { if (beanInstance instanceof NullBean) { return beanInstance; } if (!(beanInstance instanceof FactoryBean)) { throw new BeanIsNotAFactoryException(transformedBeanName(name), beanInstance.getClass()); } } // 现在我们有了个bean实例,这个实例可能会是正常的bean或者是FactoryBean,如果是FactoryBean我们使用它创建实例, //但是如果用户想要直接获取工厂实例而不是工厂的getObject方法对应的实例,那么传入的name应该加入前缀 if (!(beanInstance instanceof FactoryBean) || BeanFactoryUtils.isFactoryDereference(name)) { return beanInstance; } //加载FactoryBean开始--------------- Object object = null; if (mbd == null) { //尝试从缓存中加载bean object = getCachedObjectForFactoryBean(beanName); } if (object == null) { // 到这里就已经明确知道beanInstance一定是FactoryBean类型 FactoryBean<?> factory = (FactoryBean<?>) beanInstance; // containsBeanDefinition检查BeanDefinitionMap中也就是在所有已经加载的类中检测是否定义beanName if (mbd == null && containsBeanDefinition(beanName)) { //将存储XML配置文件的GenericBeanDefinition转换为RootBeanDefinition,如果指定beanName是子bean的话同时合并父类的信息 mbd = getMergedLocalBeanDefinition(beanName); } //是否是用户定义的而不是应用程序本身定义的 boolean synthetic = (mbd != null && mbd.isSynthetic()); object = getObjectFromFactoryBean(factory, beanName, !synthetic); } return object; }
从上面的代码来看,其实这个方法并没有什么重要的信息,大多是些辅助代码以及一些功能性的判断。由于已经注释了这么多,所以这里就不再赘述逻辑了。而真正的核心代码却委托给了getObjectFromFactoryBean方法,来看一下这个方法的源码:
protected Object getObjectFromFactoryBean(FactoryBean<?> factory, String beanName, boolean shouldPostProcess) { //如果是单例模式 if (factory.isSingleton() && containsSingleton(beanName)) { synchronized (getSingletonMutex()) { Object object = this.factoryBeanObjectCache.get(beanName); if (object == null) { 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 { if (shouldPostProcess) { if (isSingletonCurrentlyInCreation(beanName)) { // Temporarily return non-post-processed object, not storing it yet.. return object; } beforeSingletonCreation(beanName); try { object = postProcessObjectFromFactoryBean(object, beanName); } catch (Throwable ex) { throw new BeanCreationException(beanName, "Post-processing of FactoryBean's singleton object failed", ex); } finally { afterSingletonCreation(beanName); } } if (containsSingleton(beanName)) { this.factoryBeanObjectCache.put(beanName, object); } } } return object; } } else { Object object = doGetObjectFromFactoryBean(factory, beanName); if (shouldPostProcess) { try { object = postProcessObjectFromFactoryBean(object, beanName); } catch (Throwable ex) { throw new BeanCreationException(beanName, "Post-processing of FactoryBean's object failed", ex); } } return object; } }
发现这个方法还是没有做什么事情,只是做了一件事:返回的bean如果是单例的,那就必须保证全局唯一性,同时也是由于是单例的,所以没有必要重复创建,可以使用缓存来提高性能。也就是说已经加载过的就要记录下来以便于下次复用。还发现其重要的事情还是交给了doGetObjectFromFactoryBean方法:
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方法 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); } if (object == null) { if (isSingletonCurrentlyInCreation(beanName)) { throw new BeanCurrentlyInCreationException( beanName, "FactoryBean which is currently in creation returned null from getObject"); } //返回空bean object = new NullBean(); } return object; }
之前已经讲述了FactoryBean的调用方法,如果bean声明为FactoryBean类型,则当提取bean时提取的并不是FactoryBean,而是FactoryBean中对应的getObject方法返回的bean,而doGetObjectFromFactoryBean方法正是实现这个功能的。在通过getObject方法得到我们想要的结果后,并没有立即返回而是经过了postProcessObjectFromFactoryBean方法:
AbstractAutowireCapableBeanFactory类里的方法:
protected Object postProcessObjectFromFactoryBean(Object object, String beanName) { return applyBeanPostProcessorsAfterInitialization(object, beanName); }
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; }
这个方法是ObjectFactory父后处理器,以后会详细讲述,这里只需要了解在Spring中获取bean的规则中有这样一条:尽可能保证所有bean在初始化后都会调用注册的BeanPostProcessor的postProcessAfterInitialization方法进行处理。在实际的开发中,可以利用此特性设计自己的业务逻辑。
至此,从缓存中获取单例的过程结束。
参考:《Spring源码深度解析》 郝佳 编著: