spring容器管理的bean中,有一种比较特殊的类型FactoryBean,这种类型的bean,自身即是一个bean对象,也能产生其他类型的bean对象,通过接口方法便可得知
//从工厂拿到bean对象
T getObject() throws Exception
//工厂产生bean的类型
Class<?> getObjectType()
//是否为单例的
default boolean isSingleton() {
return true;
}
为何需要FactoryBean来产生bean对象,而不是直接定义好呢,这个主要是在一些特殊的场景,比如bean对象的产生过程比较复杂,需要根据一些配置信息等等。
如何从容器中获取一个bean对象?这是spring容器内部的一个实现逻辑,其中主要有三个变量要注意区分
- name,外部要获取bean对象传入的名称
- beanName,spring容器内部维护的bean对应的beanName,通常情况下name与beanName是一样的,除了FactoryBean的情况
- shareInstance ,beanName对应的bean实例
Object sharedInstance = getSingleton(beanName);
if (sharedInstance != null && args == null) {
//这里主要是为了处理FactoryBean的场景
beanInstance = getObjectForBeanInstance(sharedInstance, name, beanName, null);
}
普通的bean,根据beanName获取到的shareInstance对象就是最终要返回的对象,而FactoryBean就不太一样了
例如:程序中定义了一个User对象,还有一个UserFactoryBean,User对象没有注入到spring容器,UserFactoryBean注入了,然后UserFactoryBean的工厂方法getObject返回的是一个User对象。
那么,如果通过spring容器要获取到UserFactoryBean自身的bean实例,传入的name是&userFactoryBean,要获取User的bean实例,传入的name是userFactoryBean,若name传的是user,那么会找不到bean对象,这个也很好理解,User是通过UserFactoryBean产生的,所以传入userFactoryBean。
接下来看下spring源码是如何处理这种情况的
protected Object getObjectForBeanInstance(
Object beanInstance, String name, String beanName, @Nullable RootBeanDefinition mbd) {
//根据name判断要获取的bean是FactoryBean自身,还是其工厂方法产生的,判断的依据就是name是否有&前缀
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;
}
//假如beanInstance自身就是一个普通的bean对象,那么直接返回
if (!(beanInstance instanceof FactoryBean)) {
return beanInstance;
}
Object object = null;
if (mbd != null) {
mbd.isFactoryBean = true;
}
else {
//根据beanName获取缓存中工厂方法产生的对象
object = getCachedObjectForFactoryBean(beanName);
}
if (object == null) {
FactoryBean<?> factory = (FactoryBean<?>) beanInstance;
if (mbd == null && containsBeanDefinition(beanName)) {
mbd = getMergedLocalBeanDefinition(beanName);
}
boolean synthetic = (mbd != null && mbd.isSynthetic());
//获取工厂方法产生的bean对象,若是Singleton的,那么还会将对象缓存起来
object = getObjectFromFactoryBean(factory, beanName, !synthetic);
}
return object;
}
这个方法逻辑很简单,如果beanInstance是普通的bean,那么直接返回;如果是FactoryBean的话,那么根据name判断程序是要获取FactoryBean自身的bean实例,还是其工厂方法产生的bean实例。若是自身的,那么直接返回;若是要获取工厂产生的,那么先看缓存有没,有的话直接拿,没有的话,再进入工厂方法创建bean。
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);
// Only post-process and store if not put there already during getObject() call above
// (e.g. because of circular reference processing triggered by custom getBean calls)
Object alreadyThere = this.factoryBeanObjectCache.get(beanName);
if (alreadyThere != null) {
object = alreadyThere;
}
else {
if (shouldPostProcess) {
if (isSingletonCurrentlyInCreation(beanName)) {
// Temporarily return non-post-processed object, not storing it yet..
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;
}
}
这个方法不仅仅是执行工厂方法,有几个点要注意
- 调用完工厂方法拿到对象后,并不是直接返回,还会调用BeanPostProcessor的postProcessAfterInitialization方法。spring内置的几个processor要执行
- 会判断工厂产生的bean是否为singleton,若是的话,还会加入到factoryBeanObjectCache,这样每次获取到的bean就是单例的,不会重新走工厂方法来创建一个新对象。
以上就是从spring容器中获取FactoryBean和其工厂产生的bean的逻辑,细心的可能会发现,程序中有时并不是根据name来获取bean,而是通过Class对象,那么如果通过class对象来获取bean是如何处理的,跟踪源码会发现,也是需要根据Class类型获取到对应的name,再走上述讲的逻辑。所以重点就看下如果通过Class获取到name
private String[] doGetBeanNamesForType(ResolvableType type, boolean includeNonSingletons, boolean allowEagerInit) {
List<String> result = new ArrayList<>();
// Check all bean definitions.
for (String beanName : this.beanDefinitionNames) {
// Only consider bean as eligible if the bean name is not defined as alias for some other bean.
if (!isAlias(beanName)) {
try {
RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
// Only check bean definition if it is complete.
if (!mbd.isAbstract() && (allowEagerInit ||
(mbd.hasBeanClass() || !mbd.isLazyInit() || isAllowEagerClassLoading()) &&
!requiresEagerInitForType(mbd.getFactoryBeanName()))) {
boolean isFactoryBean = isFactoryBean(beanName, mbd);
BeanDefinitionHolder dbd = mbd.getDecoratedDefinition();
boolean matchFound = false;
boolean allowFactoryBeanInit = (allowEagerInit || containsSingleton(beanName));
boolean isNonLazyDecorated = (dbd != null && !mbd.isLazyInit());
if (!isFactoryBean) {
if (includeNonSingletons || isSingleton(beanName, mbd, dbd)) {
matchFound = isTypeMatch(beanName, type, allowFactoryBeanInit);
}
}
else {
if (includeNonSingletons || isNonLazyDecorated ||
(allowFactoryBeanInit && isSingleton(beanName, mbd, dbd))) {
matchFound = isTypeMatch(beanName, type, allowFactoryBeanInit);
}
if (!matchFound) {
// In case of FactoryBean, try to match FactoryBean instance itself next.
beanName = FACTORY_BEAN_PREFIX + beanName;
matchFound = isTypeMatch(beanName, type, allowFactoryBeanInit);
}
}
if (matchFound) {
result.add(beanName);
}
}
}
catch (CannotLoadBeanClassException | BeanDefinitionStoreException ex) {
}
catch (NoSuchBeanDefinitionException ex) {
}
}
}
//省略.......
return StringUtils.toStringArray(result);
}
这个方法的主要逻辑就是,循环spring容器的所有beanName,然后再根据isTypeMatch方法来判断当前的Class类型是否能匹配上这个beanName,若是的话,会返回。
这里不管当前beanName对应的bean是否为FactoryBean,都走的是isTypeMatch方法。所以问题的关键就在这方法内部,但是会发现如果isFactoryBean是true的话,可能需要执行两次isTypeMatch,这结合isTypeMatch方法逻辑便可知道了
protected boolean isTypeMatch(String name, ResolvableType typeToMatch, boolean allowFactoryBeanInit)
throws NoSuchBeanDefinitionException {
String beanName = transformedBeanName(name);
boolean isFactoryDereference = BeanFactoryUtils.isFactoryDereference(name);
// Check manually registered singletons.
Object beanInstance = getSingleton(beanName, false);
if (beanInstance != null && beanInstance.getClass() != NullBean.class) {
if (beanInstance instanceof FactoryBean) {
if (!isFactoryDereference) {
Class<?> type = getTypeForFactoryBean((FactoryBean<?>) beanInstance);
return (type != null && typeToMatch.isAssignableFrom(type));
}
else {
return typeToMatch.isInstance(beanInstance);
}
}
else if (!isFactoryDereference) {
if (typeToMatch.isInstance(beanInstance)) {
// Direct match for exposed instance?
return true;
}
这个方法比较长,只挑前面一部分代码就可以大概的理解逻辑了
根据beanName获取到bean对象,如果bean对象只是普通类型的,那么就直接对比对象是否为ResolvableType 的,若是则匹配成功(实际会复杂一些)
若bean对象是FactoryBean的,那么根据传进来的name是否要获取FactoryBean自身的,若是的话,也是直接比较(和普通类型的一样)。若不是,说明要获取的是工厂方法产生的bean,那么需要调用FactoryBean的getObjectType方法,来判断工厂返回的类型能否匹配上ResolvableType