前言
在实际开发当中,如果偏向于系统基础架构开发的话,对于FactoryBean的使用应该不会特别陌生。FactoryBean和BeanFactory这二者经常会被拿出来比较,原因在于这二者的名字看起来很容易让人混淆,然而这二者的原理和作用完全不一样。本篇文章将围绕FactoryBean展开源码解析。
FactoryBean接口
public interface FactoryBean<T> {
// 返回创建的bean对象
T getObject() throws Exception;
// bean对象的Class类型
Class<?> getObjectType();
// bean对象是否是单例,默认为单例。
default boolean isSingleton() {
return true;
}
}
我们来写一个类测试一下,看看能够从容器中获取到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));
}
}
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;
}
我们重点关注的是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底层的复杂构建。如果工作中也有遇到类似的场景的话,可以借鉴此思路。