containsBean方法的作用就是判断IoC容器中是否包含指定名称的Bean。该方法由BeanFactory接口定义,由AbstractBeanFactory实现。
判断IoC容器中是否包含指定beanName是从三个维度去判断的:
一、当前IoC容器的一级缓存(singletonObjects)中是否包含指定beanName的实例;
二、当前IoC容器中是否包含指定beanName的BeanDefinition信息;
三、当前IoC容器如果存在父容器,那么父容器是否存在指定beanName的Bean或者BeanDefinition信息。
了解了判断逻辑后,接下来再分析该方法的执行逻辑就十分简单。在该实现中,首先调用tranforme-dBeanName方法来对传入的name进行处理,接下来便是调用containsSingleton方法来判断当前IoC容器中的一级缓存(singletonObjects)中是否包含指定beanName的实例,调用containsBeanDefinition方法来判断当前IoC容器中是否包含指定beanName的BeanDefinition信息。
如果当前IoC容器中包含指定name的Bean实例或者BeanDefinition,接下来会再做一次验证,判断指定name所对应的Bean类型(注意,这里讲的Bean类型,指的是更宽泛的概念,IoC容器中的Bean大体可以分为两种类型:一种是普通Bean,一种是FactoryBean)。
调用BeanFactoryUtils的isFactoryDereference方法来判断传入的name是否是一个FactoryBean的beanName,注意这里是对判断结果取反。如果该判断不成立,则意味着传入的name所对应的Bean必定是一个FactoryBean,调用isFactoryBean方法来进行验证。
以上是当前IoC容器中存在指定name的Bean实例或者BeanDefinition信息的场景,如果当前IoC容器不存在,那么则判断当前IoC容器其父容器是否不等于空,并调用父容器的containsBean方法,返回父容器的判断结果(这是一个递归查找,假设父容器也有父容器,层层查找)。
// AbstractBeanFactory#containsBean
@Override
public boolean containsBean(String name) {
String beanName = transformedBeanName(name);
if (containsSingleton(beanName) || containsBeanDefinition(beanName)) {
return (!BeanFactoryUtils.isFactoryDereference(name) || isFactoryBean(name));
}
// Not found -> check parent.
BeanFactory parentBeanFactory = getParentBeanFactory();
return (parentBeanFactory != null && parentBeanFactory.containsBean(originalBeanName(name)));
}
// DefaultSingletonBeanRegistry#containsSingleton
@Override
public boolean containsSingleton(String beanName) {
return this.singletonObjects.containsKey(beanName);
}
// DefaultListableBeanFactory#containsBeanDefinition
@Override
public boolean containsBeanDefinition(String beanName) {
Assert.notNull(beanName, "Bean name must not be null");
return this.beanDefinitionMap.containsKey(beanName);
}
BeanFactoryUtils的isFactoryDereference方法实现很简单,判断传入的name不等于空,并且name是以“&”开始。
String FACTORY_BEAN_PREFIX = "&";
public static boolean isFactoryDereference(@Nullable String name) {
return (name != null && name.startsWith(BeanFactory.FACTORY_BEAN_PREFIX));
}
isFactoryBean方法由ConfigurableBeanFactory接口定义,由AbstractBeanFactory类实现,在该实现中,首先调用transformedBeanName方法对传入的name进行处理,接下来调用getSingleton方法来获取IoC容器中的一级缓存或二级缓存中是否存在指定beanName的实例,如果存在,则判断是否是FactoryBean类型。
如果getSingleton方法返回值为空,则判断当前IoC容器是否不包含指定beanName的BeanDefinition信息并且当前IoC容器存在父容器并且父容器是ConfigurableBeanFactory类型。如果判断成立,则调用父容器的isFactoryBean方法并返回。
最后调用重载的isFactoryBean方法,首先获取beanName所对应的BeanDefinition,然后根据BeanD-efinition信息来判断指定beanName所对应的Bean是否是一个FactoryBean。
// AbstractBeanFactory#isFactoryBean
@Override
public boolean isFactoryBean(String name) throws NoSuchBeanDefinitionException {
String beanName = transformedBeanName(name);
Object beanInstance = getSingleton(beanName, false);
if (beanInstance != null) {
return (beanInstance instanceof FactoryBean);
}
// No singleton instance found -> check bean definition.
if (!containsBeanDefinition(beanName) && getParentBeanFactory() instanceof ConfigurableBeanFactory) {
// No bean definition found in this factory -> delegate to parent.
return ((ConfigurableBeanFactory) getParentBeanFactory()).isFactoryBean(name);
}
return isFactoryBean(beanName, getMergedLocalBeanDefinition(beanName));
}
IoC容器的containsBean方法拥有层次性判断能力,即当前容器→父容器→父容器的父容器…层层进行查找。
用该方法来判断IoC容器中是否包含某个Bean,即使返回值为true,但不代表指定beanName所关联的Bean已经被初始化,因为通过上面代码分析可以得知支撑其判断的数据来源部分是来自beanDefi-nitionMap。
另外通过registerSingleton方法注册的Bean也是支撑IoC容器用来判断的数据来源,因为通过该方法注册的Bean是直接被保存进singletonObjects中,即一级缓存。