FactoryBean接口
FactoryBean接口很简单,定义了如下几个方法
public interface FactoryBean<T> {
String OBJECT_TYPE_ATTRIBUTE = "factoryBeanObjectType";
/**
* 返回创建的Bean对象
*/
@Nullable
T getObject() throws Exception;
/**
* 返回对象的类型
*/
@Nullable
Class<?> getObjectType();
/**
*是否单例
*/
default boolean isSingleton() {
return true;
}
FactoryBean的使用
FactoryBean用于手动控制一个Bean的创建,相对于正常的SpringBean,可以更加自由的指定Bean的创建。
示例
@Component("userFromFactory")
public class MyFactoryBean implements FactoryBean<User> {
@Override
public User getObject() {
return new User();
}
@Override
public Class<?> getObjectType() {
return User.class;
}
}
测试类
public class Test {
/**
*
*/
public static void main(String[] args) {
// 创建一个Spring容器
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(AppConfig.class);
User userFromFactory = applicationContext.getBean("userFromFactory", User.class);
System.out.println(userFromFactory);
}
}
输出结果
可以看到,成功创建了User对象,并从容器中可以根据BeanFactory的名称获取到生产的Bean。
这与我们一般getBean的结果不太一样,一般我们根据beanName获取到的是Bean本身,让我们接
着看getBean("$userFromFactory")
的结果
此时没有返回生产的Bean,而是直接返回了FactoryBean对象本身,我们可以猜测:
FactoryBean在IOC容器内是‘&name’的形式存储,而生产的Bean是以'name'的形式存储
究竟是不是这样呢?让我们看getBean方法
源码解析
1. 获取&userFromFactory
首先,我们看getBean是如何获取&userFromFactory对象的
进入方法可以看到第一步transformedBeanName
方法把&userFromFactory转换成了userFromFactory,接着从
对象池中获取到了FactoryBean对象
获取到之后并没有直接返回,进了getObjectForBeanInstance
方法
这里BeanFactoryUtils.isFactoryDereference(name)
先判断了beanName是否是以&开头,如果是以&开头,直接将前面从对象池中获取到的Bean返回,所以直接从此返回了FactoryBean对象。
我们可以得出部分结论:在IOC容器中FactoryBean对象是跟本身名称映射的,而不是跟&name
去容器中验证一下,确实如此
2. 获取userFromFactory(生产出的对象)
前面的步骤一样,当我们走到getObjectForBeanInstance
方法后
尝试从缓存中取对象(思考一下也比较合理,因为factoryBean同样可以被定义为单例,自然应该有对应的缓存池),当我们首次获取时是没有值的,所以继续往下走
最终是通过getObjectFromFactoryBean -> doGetObjectFromFactoryBean
中调用了facotryBean本身的getObject对对象进行了创建,并且创建后放到缓存中保证单例唯一性。
结论
FactoryBean的对象池跟IOC容器并不在一起,是单独保存在
FactoryBeanRegistrySupport
类的factoryBeanObjectCache
中