读完这篇文章你将会收获到
在 ``getBean` 方法中, `Spring` 处理别名以及 `factoryBean` 的 `name``
``Spring` 如何从多级缓存中根据 `beanName` 获取 `bean``
``Spring` 如何处理用户获取普通 `bean` 和 `factoryBean`` 
引言
从 Spring 容器的初始化 中,我们了解到 ``Spring` 是如何将 `XML` 文件转换为 `BeanDefinition` 并注册到 `BeanDefinitionRegstry`` 。
今天我们一起继续学习 ``Spring` 的 `bean`` 加载
public static void main(String[] args) {
		Resource resource = new ClassPathResource("coderLi.xml");
		DefaultListableBeanFactory defaultListableBeanFactory = new DefaultListableBeanFactory();
		XmlBeanDefinitionReader xmlBeanDefinitionReader = new XmlBeanDefinitionReader(defaultListableBeanFactory);
		xmlBeanDefinitionReader.loadBeanDefinitions(resource);
	}
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN 2.0//EN" "https://www.springframework.org/dtd/spring-beans-2.0.dtd">
<beans>
	<bean class="com.demo.data.Person">
		<description>
			微信搜一搜:CoderLi
		</description>
	</bean>
``熟悉的味道、熟悉的配方``
源码分析
我们可以在上面的 Java 代码中加入以下的代码
System.out.println(defaultListableBeanFactory.getBean("com.demo.data.Person#0"));
我们根据默认的 beanName 从 Spring 容器中获取 Person 这个 bean 对象,当然我们可以使用默认的别名获取
System.out.println(defaultListableBeanFactory.getBean("com.demo.data.Person"));
对 Spring 别名不熟悉的朋友可以先看下我的这一篇文章 Spring-AliasRegistry
我们直接进入到  ``AbstractBeanFactory#getBean(String)` 方法中, `AbstractBeanFactory` 为 `DefaultListableBeanFactory`` 的父类
@Override
public Object getBean(String name) throws BeansException {
   return doGetBean(name, null, null, false);
}
可以看到 ``do` 开头的才是真正干活的老大 , `AbstractBeanFactory#doGetBean`` 
protected <T> T doGetBean(final String name, @Nullable final Class<T> requiredType,
                    @Nullable final Object[] args, boolean typeCheckOnly) throws BeansException {
   
   final String beanName = transformedBeanName(name);
   Object bean;
   
   
   Object sharedInstance = getSingleton(beanName);
   if (sharedInstance != null && args == null) {
      
      
      bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);
   }
 ..........
 ...........
因为这个方法实在太长了所以截取一部分、我们一步步来分析
``transformedBeanName(name)`` 这个方法就是将我们的 name 转换为真正的 beanName,因为我们传进来的参数可能是一个 alias 或者可能是一个 factoryBean 的 beanName (前缀为&),而我们在 Spring 中存放的 factoryBean 的 beanName 是没有 & 前缀的,所以需要处理掉这个前缀
protected String transformedBeanName(String name) {
   return canonicalName(BeanFactoryUtils.transformedBeanName(name));
}
public static String transformedBeanName(String name) {
		Assert.notNull(name, "'name' must not be null");
		
		if (!name.startsWith(BeanFactory.FACTORY_BEAN_PREFIX)) {
			return name;
		}
		
		return transformedBeanNameCache.computeIfAbsent(name, beanName -> {
			do {
				beanName = beanName.substring(BeanFactory.FACTORY_BEAN_PREFIX.length());
			}
			while (beanName.startsWith(BeanFactory.FACTORY_BEAN_PREFIX));
			return beanName;
		});
	}
	
	 * 找到这个别名的最终的 bean Name、如果没有的话(
	 * 也就是说参数中的name 就是人家的 bean name 那么就直接返回这个 参数就行了)
	 *
	 */
	public String canonicalName(String name) {
		String canonicalName = name;
		
		String resolvedName;
		do {
			resolvedName = this.aliasMap.get(canonicalName);
			if (resolvedName != null) {
				canonicalName = resolvedName;
			}
		}
		while (resolvedName != null);
		return canonicalName;
	}
让我们再看看下一个方法 ``DefaultSingletonBeanRegistry#getSingleton(String)`` 
public Object getSingleton(String beanName) {
   
   return getSingleton(beanName, true);
}
@Nullable
protected Object getSingleton(String beanName, boolean allowEarlyReference) {
   Object singletonObject = this.singletonObjects.get(beanName);
   
   if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
      
      synchronized (this.singletonObjects) {
         
         singletonObject = this.earlySingletonObjects.get(beanName);
         
         if (singletonObject == null && allowEarlyReference) {
            
            ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
            if (singletonFactory != null) {
               singletonObject = singletonFactory.getObject();
               
               this.earlySingletonObjects.put(beanName, singletonObject);
               
               this.singletonFactories.remove(beanName);
            }
         }
      }
   }
   return singletonObject;
}
上面的代码就是 Spring 尝试从缓存中加载单例。单例在 Spring 的同一个容器中只会被创建一次,后续再获取 bean,就直接从缓存中取了。
在介绍这个方法之前、我们先认识下 ``DefaultSingletonBeanRegistry`` 这个类里面的成员变量吧
``Map<String, Object> singletonObjects`` 这个很好理解、 key 就是 beanName ,value 就是 bean 实例
``Map<String, ObjectFactory<?>> singletonFactories `` key 为 beanName,value 为创建 bean 的工厂
``Map<String, Object> earlySingletonObjects` key 为 beanName ,value 为 bean。但是和 `singletonObjects` 不同的是,bean 被加入到 `earlySingletonObjects`` 的时候、这个 bean 还是处于一种创建中的状态,目的也很简单、Spring 用来解决某些场景下的循环依赖
我们再回到代码中、分析一下它的逻辑
先从 singletonObjects 中尝试获取 bean,这里存放的是已经创建好的 bean 了、如果在这里能知道、那当然是最好啦
如果在这里找不到的话、那么我们就要判断下这个 beanName 对应的 bean 是否正在创建中
如果是的话,那么我们再看看这个正在创建的 bean 是否已经曝光出来、如果没有的话、那么就要看看我们的参数是否允许依赖早期的 bean 了、
如果允许早期依赖、那么我们就尝试冲 ObjectFactory 中获取到对应的 bean、并将它放入到 earlySingletonObjects 中、并从 singletonFactories 中移除
类似多级缓存的设计
在上面的方法中我们看到 ``isSingletonCurrentlyInCreation(beanName)`` 这个方法、
public boolean isSingletonCurrentlyInCreation(String beanName) {
   return this.singletonsCurrentlyInCreation.contains(beanName);
}
``singletonsCurrentlyInCreation`` 这个 Set 中,当创建一个 bean 之前会将其 对应的 beanName 放置到这个 Set 中、后面的分析会涉及到、这里先提一嘴 
我们第一次获取这个 bean 、返回为 null 是正常的
那假如我们在代码中 getBean 了两次
defaultListableBeanFactory.getBean("com.demo.data.Person#0")
defaultListableBeanFactory.getBean("com.demo.data.Person#0")
那么针对第二次的调用、返回的值就不是为 null 了 
 Object sharedInstance = getSingleton(beanName);
   if (sharedInstance != null && args == null) {
      
      bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);
   }
我们先假设 sharedInstance 不为 null 也就是我们第二次调用 ``getBean` ,我们进入到 `getObjectForBeanInstance`` 方法中
protected Object getObjectForBeanInstance(
      Object beanInstance, String name, String beanName, @Nullable RootBeanDefinition mbd) {
    
   if (BeanFactoryUtils.isFactoryDereference(name)) {
      
      if (beanInstance instanceof NullBean) {
         return beanInstance;
      }
      
      if (!(beanInstance instanceof FactoryBean)) {
         throw new BeanIsNotAFactoryException(beanName, beanInstance.getClass());
      }
      if (mbd != null) {
         mbd.isFactoryBean = true;
      }
      return beanInstance;
   }
    
   if (!(beanInstance instanceof FactoryBean)) {
      return beanInstance;
   }
   
   Object object = null;
   if (mbd != null) {
      mbd.isFactoryBean = true;
   } else {
      
      object = getCachedObjectForFactoryBean(beanName);
   }
   
   if (object == null) {
      
      FactoryBean<?> factory = (FactoryBean<?>) beanInstance;
      
      if (mbd == null && containsBeanDefinition(beanName)) {
         mbd = getMergedLocalBeanDefinition(beanName);
      }
      
      boolean synthetic = (mbd != null && mbd.isSynthetic());
      object = getObjectFromFactoryBean(factory, beanName, !synthetic);
   }
   return object;
}
我们按步骤分析下上面的代码
我们调用 ``getBean(name)`` 中的 name 如果包含前缀 & ,表面我们是想要从 Spring 中获取一个 FactoryBean ,那么我们就要判断我们从缓存中获取的 beanInstance 是否是 一个 FactoryBean 、如果是的话就直接返回不是的话就要抛出异常了
我们想要的是一个非 factoryBean 并且 在 spring 容器中找到了非 factoryBean 的 bean、那么就直接返回 
我们想要的是一个 非 factoryBean 但是在 spring 容器中找到了一个 factoryBean 的 bean、那么就要进入到 ``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);
            
            Object alreadyThere = this.factoryBeanObjectCache.get(beanName);
            if (alreadyThere != null) {
               
               object = alreadyThere;
            } else {
               
               if (shouldPostProcess) {
                  
                  if (isSingletonCurrentlyInCreation(beanName)) {
                     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;
   }
}
啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊、代码很长长长..........我们一点点来分析
第一步就是判断这个 factoryBean 是否是单例、如果不是的话,并且是用户自己定义的 bean、那么就需要调用 ``postProcessObjectFromFactoryBean`` 方法去做一个后续的处理
   1. 这里面最终回调的就是我们常用的一个接口 ``BeanPostProcessor`` 
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;
   	}
如果这 beanFactory 是一个单例,那我们就看看 factoryBeanObjectCache ( key 是 beanName,value 是 beanFactory 产生出来的 object 也是我们正要获取的 bean  ) 这个 Map 中是否存在这个 beanName 这个 bean
如果存在的话、就直接返回、如果不存在的话、那就 ``doGetObjectFromFactoryBean`` ,从这个方法中使用 FactoryBean#getObject 产生 bean 
其实下面这段代码确实让人看不懂哦
    
 Object alreadyThere = this.factoryBeanObjectCache.get(beanName);
   if (alreadyThere != null) {
   
   object = alreadyThere;
   }
然后我们看到 ``beforeSingletonCreation` 这个方法、就是上面  `getSingleton` 中 `isSingletonCurrentlyInCreation`` 判断一个 bean 是否处于正在创建中
     
protected void beforeSingletonCreation(String beanName) {
   		if (!this.inCreationCheckExclusions.contains(beanName) && !this.singletonsCurrentlyInCreation.add(beanName)) {
   			throw new BeanCurrentlyInCreationException(beanName);
   		}
   	}
   	public boolean isSingletonCurrentlyInCreation(String beanName) {
   		return this.singletonsCurrentlyInCreation.contains(beanName);
   	}
然后又调用到 ``postProcessObjectFromFactoryBean` 方法、最终回调的就是我们常用的一个接口 `BeanPostProcessor``
最好调用 ``afterSingletonCreation(beanName)` 方法、将其从 正在创建中的 bean 的集合中移除、最后的最后、将其加入到 `factoryBeanObjectCache`` 集合中 
今天我们就先分析到这里、后续的话我们在后面的文章继续探讨。今天我们大致分析了 getBean 里面的这三个方法
总结
  - 先从一级缓存 ``singletonObjects`` 中看看有没有
  - 然后从二级缓存 ``earlySingletonObjects``
  - 都没有的话再从三级缓存 ``singletonFactories`` 中看看有没有 
  - 如果 Spring 缓存中返回的 bean 是 factoryBean、而用户也想要的是一个 beanFactory (参数 name 中的前缀是 ``&`` )、那么我们直接返回
  - 如果 Spring 缓存中返回的 bean 是普通的 bean、而用户也想要的是一个普通的 bean 、那么就直接返回
  - 如果 Spring 缓存中返回的 bean 是一个 factoryBean、而用户想要的是一个普通的 bean 、那么我们就要从 factoryBean 中获取这个 bean
  - 而从 factoryBean 中获取这个 bean的过程中、需要调用到前置处理、后置处理和我们常用的接口回调 ``BeanPostProcessor``
上面的三个方法大致流程就是这样、希望对各位有帮助
有兴趣进入群聊、一起交流一起划水
评论