Spring 5.x 源码之旅十四isFactoryBean方法解读

isFactoryBean(String name)根据名字判断是否是FactoryBean

我们继续上篇,上篇讲了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));
	}

transformedBeanName转换后的名字

我们来看这个转换名字,其实跟上篇说的FactoryBean名字相关,我们还是来看源码吧:

	protected String transformedBeanName(String name) {
		return canonicalName(BeanFactoryUtils.transformedBeanName(name));
	}

BeanFactoryUtils的transformedBeanName

首先判断是不是有&前缀,没有就直接返回,说明不是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;
		});
	}

canonicalName取出原始名字

进行名字的规范化,其实就是取出原始名字,如果是别名就从映射中取原始名,是原始名字直接返回。

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;
	}

getSingleton(String beanName, boolean allowEarlyReference)获取单例

这个方法传入一个名字和是否允许早期引用,这个是为了解决循环依赖的问题,这个后面会讲,现在忽略就行。singletonObjects是一个ConcurrentHashMap,放已经创建好的单例,如果发现有创建好了,就直接返回,否则判断是否正在创建isSingletonCurrentlyInCreationearlySingletonObjectsHashMap,用来保存运行早期创建引用的单例,为了解决循环依赖。我们可能会奇怪,为什么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;
	}

isSingletonCurrentlyInCreation是否正在创建中

singletonsCurrentlyInCreation这个是个set存放正在创建的单例的名字,所以可以判断是否正在创建中。

	public boolean isSingletonCurrentlyInCreation(String beanName) {
		return this.singletonsCurrentlyInCreation.contains(beanName);
	}

isFactoryBean(String beanName, RootBeanDefinition mbd)根据名字和bean定义判断是否是FactoryBean

如果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中的对象,如果是的话就直接获取名字,此时的名字是没有&前缀的,也就直接获取FactoryBeangetObject()方法创建的对象。当然如果名字不是FactoryBean类型的话,就直接获取对象。
在这里插入图片描述

总结

这部分主要就是创建单例,如果发现是FactoryBean类型的话,就获取FactoryBean,然后判断是否需要立即进行getObject()方法创建的对象,需要的话就创建。如果不是FactoryBean类型的话,就直接获取创建对象。

好了,今天就到这里了,希望对学习理解有帮助,大神看见勿喷,仅为自己的学习理解,能力有限,请多包涵。

发布了235 篇原创文章 · 获赞 74 · 访问量 3万+

猜你喜欢

转载自blog.csdn.net/wangwei19871103/article/details/105036970