08、Spring源码分析:Spring中FactoryBean真相揭秘

一,FactoryBean和BeanFactory

  • FactoryBean:首先它是一个Bean,但又不仅仅是一个Bean。它是一个能生产或修饰对象生成的工厂Bean,类似于设计模式中的工厂模式和装饰器模式。它能在需要的时候生产一个对象,且不仅仅限于它自身,它能返回任何Bean的实例。
  • BeanFactory:是Spring中Bean工厂的顶层接口,也是我们常说的SpringIOC容器,它定下了IOC容器的一些规范和常用方法并管理着Spring中所有的Bean。

二,FactoryBean揭秘

定义一个FactoryBean用于生产A对象:

public class MyFactoryBean implements FactoryBean<A> {
   
     
    @Override
    public A getObject() throws Exception {
   
     
        return new A();
    }

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

在xml中把定义的MyFactoryBean注入进去:

<bean id="myFactoryBean" class="com.bobo.MyFactoryBean"></bean>

1,解析为beanDefinition

通过debug调试,当源码走完obtainFreshBeanFactory()方法后,MyFactoryBean已经解析为BeanDefinition并且放入到BeanDefinitionMap中:

*

2,实例化对象

继续调试,当我们走完finishBeanFactoryInitialization(beanFactory);方法时可以看到MyFactoryBean已经被实例化并且缓存到了singletonObjects中:

*

结论:当IOC容器启动完之后,会把FactoryBean实例化并且缓存在singletonObjects中,注意:这里实例化的并不是A对象

3,调试context.getBean(“myFactoryBean”)方法:

上面容器已经初始化完成,下面我们来通过测试代码来从spring容器中获取bean

public class Test {
   
     

    public static void main(String[] args) {
   
     
        ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
        System.out.println(context.getBean("myFactoryBean"));
    }
}

上面getBean会走到源码doGetBean中:

protected <T> T doGetBean(
			String name, @Nullable Class<T> requiredType, @Nullable Object[] args, boolean typeCheckOnly)
			throws BeansException {
   
     
    	/**
		 * 提取对应的beanName,很多人会认为此处直接使用即可,为什么还要进行转换呢?
		 * 原因在于当bean对象实现FactoryBean接口之后就会变成&beanName,同时如果存在别名,也需要把别名进行转换
		 */
		String beanName = transformedBeanName(name);
		Object bean;

		// 提前检查单例缓存中是否有手动注册的单例对象,跟循环依赖有关联
    	// 此处会获取到singletonObjects中缓存的MyBeanFactory实例对象
		Object sharedInstance = getSingleton(beanName);
		if (sharedInstance != null && args == null) {
   
     
            
			// 返回对象的实例,很多人理解不了这句话存在的意义,当你实现了FactoryBean接口的对象,需要获取具体的对象的时候就需要此方法来进行获取了
			bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);
		}
}

以上源码可以看到,Object sharedInstance = getSingleton(beanName);这句代码是去一级缓存singletonObjects中获取beanNamemyBeanFactory的对象,此处很显然能获取到容器初始化时已经缓存好了。

这里虽然已经获取到了MyBeanFactory对象,但是这并不是我们想要的,我们想要的是A对象。别急,这里还没完,我们继续向下看bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);源码:

protected Object getObjectForBeanInstance(
			Object beanInstance, String name, String beanName, @Nullable RootBeanDefinition mbd) {
   
     

		// 通过beanName判断是否有factoryBean的前缀
		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;
		}

		// 当我们有了bean的实例之后,这个实例可能是正常的bean,也可能是FactoryBean,如果是FactoryBean那么就直接创建实例,
		// 但是如果用户想要直接获取工厂实例而不是工厂的getObject方法对应的实例,那么传入的参数应该加&前缀
		if (!(beanInstance instanceof FactoryBean)) {
   
     
			return beanInstance;
		}

		Object object = null;
		if (mbd != null) {
   
     
			mbd.isFactoryBean = true;
		}
		else {
   
     
			// 尝试从缓存中加载bean
			object = getCachedObjectForFactoryBean(beanName);
		}
		if (object == null) {
   
     
			// 将beanInstance转换为FactoryBean类型
			FactoryBean<?> factory = (FactoryBean<?>) beanInstance;
			if (mbd == null && containsBeanDefinition(beanName)) {
   
     
				// 将存储xml配置文件的GernericBeanDefinition转换为RootBeanDefinition,如果指定BeanName是子Bean的话,同时会合并父类的相关属性
				mbd = getMergedLocalBeanDefinition(beanName);
			}
			//判断当前bean是否是用户定义的,而不是应用程序本身定义的
			boolean synthetic = (mbd != null && mbd.isSynthetic());
			object = getObjectFromFactoryBean(factory, beanName, !synthetic);
		}
		return object;
	}

String FACTORY_BEAN_PREFIX = "&";
public static boolean isFactoryDereference(@Nullable String name) {
   
     
		return (name != null && name.startsWith(BeanFactory.FACTORY_BEAN_PREFIX));
	}

以上代码:如果name是以&开头的,那么意思是获取FactoryBean的实例,则直接返回,如:

context.getBean("&myFactoryBean")

这样获取的是FactoryBean实例。

但是此时我们获取的是这种形式:

context.getBean("myFactoryBean")

那么继续往下走:

protected Object getObjectFromFactoryBean(FactoryBean<?> factory, String beanName, boolean shouldPostProcess) {
   
     
		if (factory.isSingleton() && containsSingleton(beanName)) {
   
     
			synchronized (getSingletonMutex()) {
   
     
                // 从缓存中获取,如果能取到直接返回,否则调用doGetObjectFromFactoryBean方法获取实例
				Object object = this.factoryBeanObjectCache.get(beanName);
				if (object == null) {
   
     
					object = doGetObjectFromFactoryBean(factory, beanName);
					Object alreadyThere = this.factoryBeanObjectCache.get(beanName);
					if (alreadyThere != null) {
   
     
						object = alreadyThere;
					}
					else {
   
     
						if (containsSingleton(beanName)) {
   
     
                            // 把获取到的实例缓存到factoryBeanObjectCache中,下次再取时直接从集合中获取就行了
							this.factoryBeanObjectCache.put(beanName, object);
						}
					}
				}
				return object;
			}
		}
		else {
   
     
			Object object = doGetObjectFromFactoryBean(factory, beanName);
			// 省略了后置处理器的调用
			return object;
		}
	}

先从factoryBeanObjectCache缓存中获取,如果缓存中没有那么调用doGetObjectFromFactoryBean()方法:

private Object doGetObjectFromFactoryBean(FactoryBean<?> factory, String beanName) throws BeanCreationException {
   
     
		Object object;
		// 直接调用getObject方法,返回具体的对象
		object = factory.getObject();
		
		return object;
	}

通过factory.getObject()直接回调到MyFactoryBean的getObject()方法中

public class MyFactoryBean implements FactoryBean<A> {
   
     
    @Override
    public A getObject() throws Exception {
   
     
        return new A();
    }

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

直接获取到A对象,然后再缓存到factoryBeanObjectCache中,最终返回的是A对象的实例。

如果是单例情况下,下次再获取就直接从factoryBeanObjectCache缓存中取到了。

三,总结

  • getBean(beanName):获取的是FactoryBean中getObject()方法返回的对象实例,其缓存在factoryBeanObjectCache中,第一次获取时才会创建(指的是默认单例对象)。
  • getBean(&beanName):获取的是FactoryBean实例对象,其缓存在singletonObjects中,spring容器初始化完成就已经创建(指的是默认单例对象)。