我们继续上篇,上篇讲了getMergedLocalBeanDefinition
,以及为什么要用这个,本篇来讲后面的isFactoryBean
方法,怎么来判断一个beanName
是否是FactoryBean
类型。getBean
比较复杂,后面一起讲,暂时知道这个可以获取对象就好,本篇讲这部分:
@Override
public boolean isFactoryBean(String name) throws NoSuchBeanDefinitionException {
String beanName = transformedBeanName(name);//获取转换后的名字
Object beanInstance = getSingleton(beanName, false);
if (beanInstance != null) {//如果已经是单例了,就判断是否是FactoryBean类型
return (beanInstance instanceof FactoryBean);
}
// 没有单例,看是否有bean定义,没有就看父类bean工厂
if (!containsBeanDefinition(beanName) && getParentBeanFactory() instanceof ConfigurableBeanFactory) {
return ((ConfigurableBeanFactory) getParentBeanFactory()).isFactoryBean(name);
}
return isFactoryBean(beanName, getMergedLocalBeanDefinition(beanName));
}
我们来看这个转换名字,其实跟上篇说的FactoryBean
名字相关,我们还是来看源码吧:
protected String transformedBeanName(String name) {
return canonicalName(BeanFactoryUtils.transformedBeanName(name));
}
首先判断是不是有&
前缀,没有就直接返回,说明不是FactoryBean
的名字,否则就从缓存里获取,然后把前缀&
去掉返回。
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;
});
}
进行名字的规范化,其实就是取出原始名字,如果是别名就从映射中取原始名,是原始名字直接返回。
public String canonicalName(String name) {
String canonicalName = name;
// Handle aliasing...
String resolvedName;
do {
resolvedName = this.aliasMap.get(canonicalName);
if (resolvedName != null) {
canonicalName = resolvedName;
}
}
while (resolvedName != null);
return canonicalName;
}
这个方法传入一个名字和是否允许早期引用,这个是为了解决循环依赖的问题,这个后面会讲,现在忽略就行。singletonObjects
是一个ConcurrentHashMap
,放已经创建好的单例,如果发现有创建好了,就直接返回,否则判断是否正在创建isSingletonCurrentlyInCreation
,earlySingletonObjects
是HashMap
,用来保存运行早期创建引用的单例,为了解决循环依赖。我们可能会奇怪,为什么earlySingletonObjects
不是ConcurrentHashMap
,其实因为他所有的操作,都是在synchronized
同步块中了,所以不需要了,而singletonObjects
则可以在没有同步块的地方使用。继续说,如果在earlySingletonObjects
也没找到,又是允许早期引用的,就从单例singletonFactories
工厂中获取一个工厂,其实就是一个可以获取对象的工厂,只要存在,就能通过getObject()
获取,然后放进earlySingletonObjects
,删除工厂,其实有循环引用的时候就可以派上用了,后面会说。
@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;
}
singletonsCurrentlyInCreation
这个是个set存放正在创建的单例的名字,所以可以判断是否正在创建中。
public boolean isSingletonCurrentlyInCreation(String beanName) {
return this.singletonsCurrentlyInCreation.contains(beanName);
}
如果FactoryBean
单例没获取到,此时只能通过名字和bean
定义看是否是FactoryBean
了。如果定义本身定义了isFactoryBean
,那就直接返回结果,否则需要进行类型预测,他会进行反射,看看名字对应的类是否是FactoryBean
类型的,如果预测出来的类型是FactoryBean
,那就返回true
了,否则就false
。
protected boolean isFactoryBean(String beanName, RootBeanDefinition mbd) {
Boolean result = mbd.isFactoryBean;
if (result == null) {
Class<?> beanType = predictBeanType(beanName, mbd, FactoryBean.class);
result = (beanType != null && FactoryBean.class.isAssignableFrom(beanType));
mbd.isFactoryBean = result;
}
return result;
}
如果发现名字是FactoryBean
类型的话,就会在名字前加前缀&
,然后去获取,获取完了判断是否是FactoryBean类型,是的话再判断是否需要理解创建FactoryBean
中的对象,如果是的话就直接获取名字,此时的名字是没有&前缀的,也就直接获取FactoryBean
的getObject()
方法创建的对象。当然如果名字不是FactoryBean
类型的话,就直接获取对象。
这部分主要就是创建单例,如果发现是FactoryBean
类型的话,就获取FactoryBean,然后判断是否需要立即进行getObject()
方法创建的对象,需要的话就创建。如果不是FactoryBean
类型的话,就直接获取创建对象。
好了,今天就到这里了,希望对学习理解有帮助,大神看见勿喷,仅为自己的学习理解,能力有限,请多包涵。