likes
comments
collection
share

Spring源码系列——FactoryBean源码解析

作者站长头像
站长
· 阅读数 12

前言

在实际开发当中,如果偏向于系统基础架构开发的话,对于FactoryBean的使用应该不会特别陌生。FactoryBean和BeanFactory这二者经常会被拿出来比较,原因在于这二者的名字看起来很容易让人混淆,然而这二者的原理和作用完全不一样。本篇文章将围绕FactoryBean展开源码解析。

FactoryBean接口

public interface FactoryBean<T> {
	// 返回创建的bean对象
	T getObject() throws Exception;
    // bean对象的Class类型
    Class<?> getObjectType();
    // bean对象是否是单例,默认为单例。
    default boolean isSingleton() {
		return true;
	}
}

实现FactoryBean

@Component("myDemoService")
public class MyDemoFactoryBean implements FactoryBean<MyDemoService> {
    @Override
    public MyDemoService getObject() throws Exception {
        return new MyDemoService();
    }

    @Override
    public Class<?> getObjectType() {
        return MyDemoService.class;
    }
}

我们来写一个类测试一下,看看能够从容器中获取到MyDemoFactoryBean和MyDemoService这两个bean:

@Configuration
@ComponentScan("com.leon.factorybean")
public class Config {
}
public class MyApplication {
    public static void main(String[] args) {
        AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(Config.class);
        String[] myDemoTactoryBeanNames = applicationContext.getBeanNamesForType(MyDemoFactoryBean.class);
        String[] myDemoServicBeanNames = applicationContext.getBeanNamesForType(MyDemoService.class);
        System.out.println(JsonUtil.convert(myDemoTactoryBeanNames));
        System.out.println(JsonUtil.convert(myDemoServicBeanNames));
    }
}

执行结果如下:

["&myDemoService"]
["myDemoService"]

可以看到,确实可以从IOC容器中获取分别获取到MyDemoFactoryBean和MyDemoService这两个bean。这说明:

  • FacotryBean也是bean,受IOC容器管理;
  • FacotryBean可以生产指定的bean,即FacotryBean#getObject()返回的对象;
  • BeanName:默认情况下,FactoryBean的beanName为【&】+ 【类名<首字母小写>】;而它生产的bean的beanName就为【类名<首字母小写>】。 接下来,我们来看看FactoryBean在Spring中是如何解析的。

FactoryBean源码追踪

1.入口

在Spring当如,追踪源码的方式最直接的方式就是通过applicatonContext.getBean方式。

MyDemoFactoryBean myDemoFactoryBean = applicationContext.getBean(MyDemoFactoryBean.class);

2.委托给AbstractApplicationContext#getBean

实际调用的是AbstractApplicationContext#getBean(java.lang.Class),该方法其实也是空壳方法,实际将其委托给BeanFactory的getBean方法。

@Override
public <T> T getBean(Class<T> requiredType) throws BeansException {
    assertBeanFactoryActive();
    return getBeanFactory().getBean(requiredType);
}

3.再委托给DefaultListableBeanFactory#getBean(java.lang.Class)

getBeanFactory()实际上返回的是DefaultListableBeanFactory实例。到这里可以得知,DefaultListableBeanFactory是Spring当中的BeanFactory的默认实现。因此默认情况下,我们所说的IOC容器就是它了。本篇文章暂不会对容器做过多解析,先借助FactoryBean来初探其容貌。

4.再委托给DefaultListableBeanFactory#getBean(java.lang.Class, java.lang.Object...)

以上方法实际上还是没有做什么事情,依然是委托给getBean的一个重载方法。源码如下:

public <T> T getBean(Class<T> requiredType, @Nullable Object... args) throws BeansException {
  Assert.notNull(requiredType, "Required type must not be null");
  Object resolved = resolveBean(ResolvableType.forRawClass(requiredType), args, false);
  if (resolved == null) {
  throw new NoSuchBeanDefinitionException(requiredType);
  }
  return (T) resolved;
  }

5.再委托给DefaultListableBeanFactory#resolveBean

最终我们终于见到了庐山真面目,通过委托给内部的resolveBean()方法,改方法就是最终解析bean的方法。其源码如下:

private <T> T resolveBean(ResolvableType requiredType, @Nullable Object[] args, boolean nonUniqueAsNull) {
	// 解析bean,如果返回结果不为空,则说明已经获取到解析的bean了,直接返回即可。该方法是我们重点解析的方法,没有之一!
  NamedBeanHolder<T> namedBean = resolveNamedBean(requiredType, args, nonUniqueAsNull);
  if (namedBean != null) {
  	return namedBean.getBeanInstance();
  }
  // 如果返回的为空,则通过beanFactory来创建bean
  BeanFactory parent = getParentBeanFactory();
  if (parent instanceof DefaultListableBeanFactory) {
  	return ((DefaultListableBeanFactory) parent).resolveBean(requiredType, args, nonUniqueAsNull);
  }
  else if (parent != null) {
  	ObjectProvider<T> parentProvider = parent.getBeanProvider(requiredType);
  	if (args != null) {
  		return parentProvider.getObject(args);
  	}
  	else {
  		return (nonUniqueAsNull ? parentProvider.getIfUnique() : parentProvider.getIfAvailable());
  	}
  }
  return null;
}

5.DefaultListableBeanFactory#resolveNamedBean源码解析

private <T> NamedBeanHolder<T> resolveNamedBean(
			ResolvableType requiredType, @Nullable Object[] args, boolean nonUniqueAsNull) throws BeansException {

		Assert.notNull(requiredType, "Required type must not be null");
  		// 根据type获取beanName.该方法便隐藏着FactoryBean的真实身份。
		String[] candidateNames = getBeanNamesForType(requiredType);
		// 如果解析出的beanName不止1个,则自动解析到其关联的bean。
		if (candidateNames.length > 1) {
			List<String> autowireCandidates = new ArrayList<>(candidateNames.length);
			for (String beanName : candidateNames) {
				if (!containsBeanDefinition(beanName) || getBeanDefinition(beanName).isAutowireCandidate()) {
					autowireCandidates.add(beanName);
				}
			}
			if (!autowireCandidates.isEmpty()) {
				candidateNames = StringUtils.toStringArray(autowireCandidates);
			}
		}
		// 如果beanName只有1个,则直接调用getBean方法。很显然,只有一个beanName。
		if (candidateNames.length == 1) {
			String beanName = candidateNames[0];
			return new NamedBeanHolder<>(beanName, (T) getBean(beanName, requiredType.toClass(), args));
		}
		else if (candidateNames.length > 1) {
			Map<String, Object> candidates = new LinkedHashMap<>(candidateNames.length);
			for (String beanName : candidateNames) {
				if (containsSingleton(beanName) && args == null) {
					Object beanInstance = getBean(beanName);
					candidates.put(beanName, (beanInstance instanceof NullBean ? null : beanInstance));
				}
				else {
					candidates.put(beanName, getType(beanName));
				}
			}
			String candidateName = determinePrimaryCandidate(candidates, requiredType.toClass());
			if (candidateName == null) {
				candidateName = determineHighestPriorityCandidate(candidates, requiredType.toClass());
			}
			if (candidateName != null) {
				Object beanInstance = candidates.get(candidateName);
				if (beanInstance == null || beanInstance instanceof Class) {
					beanInstance = getBean(candidateName, requiredType.toClass(), args);
				}
				return new NamedBeanHolder<>(candidateName, (T) beanInstance);
			}
			if (!nonUniqueAsNull) {
				throw new NoUniqueBeanDefinitionException(requiredType, candidates.keySet());
			}
		}

		return null;
	}

我们重点关注的是getBeanNamesForType方法和getBean方法。

6.DefaultListableBeanFactory#getBeanNamesForType解析

public String[] getBeanNamesForType(ResolvableType type, boolean includeNonSingletons, boolean allowEagerInit) {
  	Class resolved = type.resolve();
  	// 这里获取到的resolved为class
  	// MyDemoFactoryBean中并没有定义其他属性,因此这里将进入if分支。
  	if (resolved != null && !type.hasGenerics()) {
  		// 这是getBeanNamesForType的一个重载方法,最终依然是调用doGetBeanNamesForType方法,请看下面的解析
  		return getBeanNamesForType(resolved, includeNonSingletons, allowEagerInit);
  	}
  	else {
  		return doGetBeanNamesForType(type, includeNonSingletons, allowEagerInit);
  	}
  }
private String[] doGetBeanNamesForType(ResolvableType type, boolean includeNonSingletons, boolean allowEagerInit) {
		List<String> result = new ArrayList<>();

		// 检查所有的beanDefinitionNames.beanDefinition在执行 new AnnotationConfigApplicationContext(Config.class)时就以及解析完毕了。因此这里可以直接遍历循环。
		for (String beanName : this.beanDefinitionNames) {
			// 判断是否有别名。一般情况下,我们很少有使用别名的情况。在本例中也一样无别名,因此进入if分支
			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()))) {
                        // !!! 重要!这里将根据beanName和beanDefinition来判断当前type是否FactoryBean类型。这个参数是区分普通bean和factoryBean的核心。
                        // 请看下面的第7小节的isFactoryBean()方法解析
						boolean isFactoryBean = isFactoryBean(beanName, mbd);
						BeanDefinitionHolder dbd = mbd.getDecoratedDefinition();
                        // !!! 重要!是否类型匹配,默认为false.
						boolean matchFound = false;
                        // 是否允许FactoryBean初始化,默认情况下是允许的
						boolean allowFactoryBeanInit = allowEagerInit || containsSingleton(beanName);
						boolean isNonLazyDecorated = dbd != null && !mbd.isLazyInit();
						// 接下来,主要是设置matchFound参数。
                        // 如果不是factoryBean类型,则直接调用isTypeMatch方法来设置matchFound参数,普通bean都是走的这个逻辑。
						if (!isFactoryBean) {
							if (includeNonSingletons || isSingleton(beanName, mbd, dbd)) {
								matchFound = isTypeMatch(beanName, type, allowFactoryBeanInit);
							}
						}
                        // 如果是factoryBean,进入下面这个else分支
						else  {
						// 首先根据普通的beanName来尝试设置matchFound,如果为true,说明找的是FactoryBean中产生的beanName。
							if (includeNonSingletons || isNonLazyDecorated ||
									(allowFactoryBeanInit && isSingleton(beanName, mbd, dbd))) {
								matchFound = isTypeMatch(beanName, type, allowFactoryBeanInit);
							}
                            // !!!重要! 如果matchFound依然为false,则说明很有可能是找FactoryBean本身,那么对beanName添加前缀:&,来尝试寻找FactoryBean本身。
							if (!matchFound) {
								// In case of FactoryBean, try to match FactoryBean instance itself next.
								beanName = FACTORY_BEAN_PREFIX + beanName;
								matchFound = isTypeMatch(beanName, type, allowFactoryBeanInit);
							}
						}
                        // 如果matchFound为true,则将beanName添加到result中。注意,如果我们找的是FactoryBean类型的话,则beanName已经被添加&前缀了。
						if (matchFound) {
							result.add(beanName);
						}
					}
				}
				catch (CannotLoadBeanClassException | BeanDefinitionStoreException ex) {
					if (allowEagerInit) {
						throw ex;
					}
					// Probably a placeholder: let's ignore it for type matching purposes.
					LogMessage message = (ex instanceof CannotLoadBeanClassException) ?
							LogMessage.format("Ignoring bean class loading failure for bean '%s'", beanName) :
							LogMessage.format("Ignoring unresolvable metadata in bean definition '%s'", beanName);
					logger.trace(message, ex);
					onSuppressedException(ex);
				}
			}
		}
        // ...省略其他代码...
        // 返回找到的beanName结果
		return StringUtils.toStringArray(result);
	}

7.AbstractBeanFactory#isFactoryBean解析

我们知道,如何判断是否是FactoryBean类型就是通过isFactoryBean()方法来解析的,其源码如下:

protected boolean isFactoryBean(String beanName, RootBeanDefinition mbd) {
		Boolean result = mbd.isFactoryBean;
		// 如果beanDefinition中的isFactoryBean属性为null,则直接获取bd中的beanType并判断是否是FactoryBean
        // 然后将判断结果赋值给bd的isFactoryBean属性,然后直接返回结果。
		if (result == null) {
			Class<?> beanType = predictBeanType(beanName, mbd, FactoryBean.class);
			result = (beanType != null && FactoryBean.class.isAssignableFrom(beanType));
			mbd.isFactoryBean = result;
		}
		return result;
}

8.AbstractBeanFactory#getBean(java.lang.String, java.lang.Class, java.lang.Object...)

在ApplicationContext中getBea方法有很多重载,但其实最终都是解析出beanName,根据beanName来找到具体的bean。原因在于:在ApplicationContext中,beanDefinition、beanType、IOC容器等都是基于beanName来做映射关系的。因此我们在阅读源码时,可以发现很多时候都是首先解析出beanName再做进一步操作。又因为beanName的定义方式多种多样,因此解析过程也比较复杂,我们在解析源码时一定要静下心来。由于getBean方法本身涉及到bean的生命周期、循环依赖等复杂场景,所以将getBean方法单独拿出来进行解析。本篇文章我们只需要知道getBean方法能够获取到实际的bean即可。

总结

通过以上解析,我们大致知道了FactoryBean的运作原理。从源码中也可以得出几个结论:

  • FactoryBean本身就是一个比较特殊的bean;
  • FactoryBean可以通过它的接口定义来生产一个普通bean;
  • FactoryBean的beanName就是它生产的普通bean的beanName加一个“&”前缀,这也间接说明普通bean不可以使用“&”作为beanName的前缀,否则在启动时,容器会报错。

FactoryBean在我们的日常开发当中,如果用的好的能有奇效。具体效果可参考Spring是如何集成Mybatis的,它其实就是通过SqlSessionFactoryBean作为入口的,而SqlSessionFactoryBean其实就是一个FactoryBean。利用它屏蔽了Mybatis底层的复杂构建。如果工作中也有遇到类似的场景的话,可以借鉴此思路。

转载自:https://juejin.cn/post/6856337888687489038
评论
请登录