由于bean对象的产生和获取过去繁琐,所有将bean的获取和产生分成两部分来讲,这里我们只讨论spring是如何获取到单例bean对象的。
spring在缓存中获取单例bean的逻辑
用于储存bean的四种不同的map:
singletonObjects:用于保存BeanName和创建bean实例之间的关系,bean name->bean instance。
singletonFactories:用于保存BeanName和创建bean的工厂之间的关系,bean name->ObjectFactory
earlySingletonObjects:也是保存BeanName和创建bean实例之间的关系,与singletonObjects的不同之处在于,当一个单例bean被放到这里面后,那么当bean还在创建过程中,就可以通过getBean方法获取到了,其目的是用来检测循环引用。
registeredSingletons:用来保存当前所有已注册的bean。
protected Object getSingleton(String beanName, boolean allowEarlyReference) {
//尝试从缓存中获取bean对象
Object singletonObject = this.singletonObjects.get(beanName);
//没获取到bean并且这个单例的bean正在创建中
if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
//锁住缓存
synchronized (this.singletonObjects) {
//从创建的注册容器中查询bean
singletonObject = this.earlySingletonObjects.get(beanName);
//创建的注册容器中也没有找到bean,并且allowEarlyReference(允许过早的查看)表示为true
if (singletonObject == null && allowEarlyReference) {
//从单例工厂中获取这个bean的创建工厂
ObjectFactory> singletonFactory = this.singletonFactories.get(beanName);
//如果已经可以获取工厂
if (singletonFactory != null) {
//通过工厂创建bean
singletonObject = singletonFactory.getObject();
//将bean放入注册容器中用于循环依赖的处理
this.earlySingletonObjects.put(beanName, singletonObject);
//将bean的工厂对象从单例工厂中删除
this.singletonFactories.remove(beanName);
}
}
}
}
//最后返回获取到的bean对象
return (singletonObject != NULL_OBJECT ? singletonObject : null);
}
用为在创建单例bean的时间会存在依赖注入的情况,而在创建依赖的时候为了避免循环依赖,Spring创建bean的原则是不等bean创建完成就会创建bean的ObjectFactory提前曝光加入到缓存中,一旦下一个bean创建时需要依赖上一个bean,则直接使用ObjectFactory。
具体逻辑在DefaultSingletonBeanRegistry类的getSingleton(beanName,true);方法中。
这个方法首先尝试从singletonObjects里面获取实例,如果获取不到再从earlySingletonObjects里面获取,如果还获取不到,在尝试从singletonFactories里面获取beanName对应的ObjectFactory,然后调用这个ObjectFactory的getObject来创建bean,并放到earlySingletonObjects里面去了,并且从singletonFacotorise里面remove掉这个ObjectFactory,而对于后续的所有内存操作都只为了循环依赖检测时候才使用。
从factoryBean获取bean实例
此时获取到的bean并非是我们最终想要的得到的bean对象,此时这个bean可能还是一个factoryBean,并非真正所需要的实例,这个bean还需要通过getObjectForBeanInstance(Object beanInstance, String name, String beanName, RootBeanDefinition mbd)进行处理。
protected Object getObjectForBeanInstance(
Object beanInstance, String name, String beanName, RootBeanDefinition mbd) {
//isFactoryDereference()方法是判断这个name是否以&为前缀的(&表示就是需要获取factoryBean对象)
//后一个判断此时的bean对象(也就是getSingleton()返回的bean)是否是个factoryBean
//这是一个相冲的判断,如果为true就需要抛出异常
if (BeanFactoryUtils.isFactoryDereference(name) && !(beanInstance instanceof FactoryBean)) {
throw new BeanIsNotAFactoryException(transformedBeanName(name), beanInstance.getClass());
}
//如果这个bean不是factoryBean说明已经被处理过来,直接返回就好
//或者用户需要的bean就是factoryBean也直接返回
if (!(beanInstance instanceof FactoryBean) || BeanFactoryUtils.isFactoryDereference(name)) {
return beanInstance;
}
Object object = null;
//mbd是RootBeanDefinition类型的对象,这个类实则是xml配置文件中标签解析后的对象
//标签解析后的对象分为两种:
//1.RootBeanDefinition:没有嵌套的标签和有嵌套的标签中的顶级标签解析或生成此对象
//2.ChildBeanDefinition:有嵌套的标签中的子集标签都会生成此对象
if (mbd == null) {
//从缓存中获取FactoryBean
object = getCachedObjectForFactoryBean(beanName);
}
//不巧的是缓存中并没有
if (object == null) {
//此时的bean一定是factoryBean 所以做一个强转换
FactoryBean> factory = (FactoryBean>) beanInstance;
//containsBeanDefinition会检测beanDefinitionMap中是否已经加载了beanName的定义
if (mbd == null && containsBeanDefinition(beanName)) {
//将加载的定义生成RootBeanDefinition对象
mbd = getMergedLocalBeanDefinition(beanName);
}
//这里判断这个mbd是程序本身定义的还是用户在配置中定义的
boolean synthetic = (mbd != null && mbd.isSynthetic());
//把最重要的逻辑委托给了getObjectFromFactoryBean()方法(生产用户需要的bean的具体逻辑)
object = getObjectFromFactoryBean(factory, beanName, !synthetic);
}
return object;
}
认真阅读上面的代码不难发现这个方法只是做了大量的辅助性质的工作,真正的处理逻辑被委托给了getObjectFromFactoryBean()方法,整理一下getObjectForBeanInstance()的功能
对FactoryBean做了验证
根据用户的需要,是否直接返回FactoryBean
将bean进行了强转
将处理逻辑委托给getObjectFromFactoryBean()
进入getObjectFromFactoryBean()方法
protected Object getObjectFromFactoryBean(FactoryBean> factory, String beanName, boolean shouldPostProcess) {
//判断模式是否是单例
if (factory.isSingleton() && containsSingleton(beanName)) {
//锁住单例容器singletonObjects
synchronized (getSingletonMutex()) {
//现在缓存中查询一下bean的实例是否存在
Object object = this.factoryBeanObjectCache.get(beanName);
//不存在
if (object == null) {
//从factorybean中获取bean实例,同时会将结果放入factoryBeanObjectCache中
object = doGetObjectFromFactoryBean(factory, beanName);
//有可能当执行doGetObjectFromFactoryBean()方法的时候,bean还在创建当中,所以这里再次获取
Object alreadyThere = this.factoryBeanObjectCache.get(beanName);
if (alreadyThere != null) {
object = alreadyThere;
}
else {
//bean实例存在并且需要发布
if (object != null && shouldPostProcess) {
try {
//调用objectFactory的后处理器
//早期版本中后处理器的调用是在doGetObjectFromFactoryBean()方法中的
object = postProcessObjectFromFactoryBean(object, beanName);
}
catch (Throwable ex) {
throw new BeanCreationException(beanName,
"Post-processing of FactoryBean's singleton object failed", ex);
}
}
//更新缓存中的对象
this.factoryBeanObjectCache.put(beanName, (object != null ? object : NULL_OBJECT));
}
}
return (object != NULL_OBJECT ? object : null);
}
}
else {
//不是单例模式的时候直接生成bean对象
Object object = doGetObjectFromFactoryBean(factory, beanName);
if (object != null && 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 {
//获取java的安全管理器,安全管理器的主要功能是防止未知代码对系统的破坏
if (System.getSecurityManager() != null) {
//获取控制器的上下文
AccessControlContext acc = getAccessControlContext();
try {
//这里是个线程来创建bean对象,并且通过上下文做验证
object = AccessController.doPrivileged(new PrivilegedExceptionAction
doGetObjectFromFactoryBean()方法中终于调用了factory.getObject()获取我们需要的bean对象。对象将返回给上一层然后通过后处理器进行用户自定义的最后处理。
终于看完了spring是如何尝试从缓存中获取一个bean的实例对象,我们简单的整理回顾一下逻辑:
spring通过getSingleton()方法尝试从缓存中获取已经实例化的bean对象
如果缓存中不存在,就通过单例工厂产生bean的创建工厂(FactoryBean)
FactoryBean对象交给getObjectForBeanInstance()进行验证
根据用户的需要,是否直接返回FactoryBean
将FactoryBean处理成bean实例的逻辑委托给getObjectFromFactoryBean()
不幸的是getObjectFromFactoryBean()方法也是个懒货,他没有去处理逻辑,只是做了唯一性的保证,以及bean的收尾工作(后处理器)。
doGetObjectFromFactoryBean()任劳任怨,不仅确保了安全还拿到了bean实例。
获取单例bean
别高兴的太早,事情没有这么简单!我们刚刚才看完了从单例工厂的容器(singletonFactory)中存在bean的BeanFactory的过程,那么如果BeanFactory根本不存在应该如何处理。
public Object getSingleton(String beanName, ObjectFactory> singletonFactory) {
//判断beanName不为空
Assert.notNull(beanName, "'beanName' must not be null");
//锁定单例bean容器
synchronized (this.singletonObjects) {
//尝试获取bean
Object singletonObject = this.singletonObjects.get(beanName);
if (singletonObject == null) {
//这个标识符表示是正在销毁bean
if (this.singletonsCurrentlyInDestruction) {
throw new BeanCreationNotAllowedException(beanName,
"Singleton bean creation not allowed while the singletons of this factory are in destruction " +
"(Do not request a bean from a BeanFactory in a destroy method implementation!)");
}
if (logger.isDebugEnabled()) {
logger.debug("Creating shared instance of singleton bean '" + beanName + "'");
}
//把bean记录到singletonsCurrentlyInCreation中,证明正在创建,用于循环依赖的检测
beforeSingletonCreation(beanName);
boolean newSingleton = false;
//判断并新建,记录禁止的意外情况的容器
boolean recordSuppressedExceptions = (this.suppressedExceptions == null);
if (recordSuppressedExceptions) {
this.suppressedExceptions = new LinkedHashSet();
}
try {
//使用回调方法 创建bean
singletonObject = singletonFactory.getObject();
newSingleton = true;
}
catch (IllegalStateException ex) {
// Has the singleton object implicitly appeared in the meantime ->
// if yes, proceed with it since the exception indicates that state.
singletonObject = this.singletonObjects.get(beanName);
if (singletonObject == null) {
throw ex;
}
}
catch (BeanCreationException ex) {
if (recordSuppressedExceptions) {
for (Exception suppressedException : this.suppressedExceptions) {
ex.addRelatedCause(suppressedException);
}
}
throw ex;
}
finally {
if (recordSuppressedExceptions) {
this.suppressedExceptions = null;
}
//移除缓存中对该bean正在加载的状态
afterSingletonCreation(beanName);
}
//如果是一个新的单例工厂
if (newSingleton) {
//将它添加到容器中
addSingleton(beanName, singletonObject);
}
}
return (singletonObject != NULL_OBJECT ? singletonObject : null);
}
}
这个方法用回调, 使得程序可以在单例创建的前后做一些准备及处理操作,正在的获取单例bean的方法并不在其中,准备操作包括:
检测缓存中是否加载过。
如果没有记载过,则记录beanName的正在加载状态。
加载单例前记录状态,这个并不是一个空的实现,通过singletonsCurrentlyInCreation容器来实现循环依赖的检测。
通过传入的参数来实例bean(也就是回调方法)
将对象移出singletonsCurrentlyInCreation容器,结束状态的记录
将结果记录和清除加载时的各种状态
返回结果。
回调方法的说明:
sharedInstance = getSingleton(beanName, new ObjectFactory
spring获取单例bean的过程大致如此,下一次我们将进入createBean()去寻找bean产生的真理
转载请联系我,拒绝非法盗用,违者必究。