FactoryBean 是一个特殊的 bean,为什么特殊呢?
特殊的 bean
1、FactoryBean 是一个接口,实现这个接口,可以重写 3 个方法,至少需要重写 2 个方法
public interface FactoryBean<T> {
@Nullable
T getObject() throws Exception;
@Nullable
Class<?> getObjectType();
default boolean isSingleton() {
return true;
}
}
2、通过 context.getBean("factoryBean")
获取的对象,并不是 FactoryBean 本身,而是 FactoryBean 的 getObject()
返回的对象
**
获取 bean 对象
1、获取生产出的 bean 对象
如果想要获取 FactoryBean 生产出来的 bean 对象的话,直接通过 getBean 就可以获取到生产出来的对象实例context.getBean("factoryBean")
,如返回 org.wesoft.spring.factorybean.User@23faf8f2
2、获取自身 bean 对象
如果想获取自身 bean 对象,也就是 FactoryBean 本身,那么需要在名称前面加一个 “&” **符号context.getBean("&factoryBean")
,如返回 org.wesoft.spring.factorybean.MyFactoryBean@2d6eabae
Spring 对 FactoryBean 的判断逻辑
protected String transformedBeanName(String name) {
return canonicalName(BeanFactoryUtils.transformedBeanName(name));
}
// BeanFactoryUtils.transformedBeanName(name)
public static String transformedBeanName(String name) {
Assert.notNull(name, "'name' must not be null");
// 检查是不是要获取 FactoryBean,即以 & 打头
if (!name.startsWith(BeanFactory.FACTORY_BEAN_PREFIX)) {
return name;
}
// 以 & 打头的 beanName
return transformedBeanNameCache.computeIfAbsent(name, beanName -> {
do {
// 截取掉 & 字符
beanName = beanName.substring(BeanFactory.FACTORY_BEAN_PREFIX.length());
}
while (beanName.startsWith(BeanFactory.FACTORY_BEAN_PREFIX));
return beanName;
});
}
// canonicalName(BeanFactoryUtils.transformedBeanName(name))
public String canonicalName(String name) {
String canonicalName = name;
// Handle aliasing...
String resolvedName;
do {
// 去 aliasMap 找是否有对应的 beanName
resolvedName = this.aliasMap.get(canonicalName);
if (resolvedName != null) {
canonicalName = resolvedName;
}
}
while (resolvedName != null);
return canonicalName;
}
FactoryBean 生产的出来的单例对象,不会放到 singleObjects 中,只会放到 factoryBeanObjectsCache 中
FactoryBean 与 BeanFactory 区别
FactoryBean 是一个特殊的 bean,可以生产一些特殊(复杂)的 bean 对象,可以理解为生产一种复杂的 bean 对象的工厂
BeanFactory 是一个大容器,也可以生产 bean 对象,包括 FactoryBean 的对象,一个大容器
FactoryBean 与 @Bean 的区别
@Bean 与 FactoryBean 所想要实现的功能类似,都能自定义产生 bean 对象,但是 FactoryBean 更加容易扩展(如实现一些其他接口),而 @Bean 则不能
FactoryBean 的应用场景
当需要按一些特定条件和组合产生某些对象时,可以考虑使用 FactoryBean 来实现,典型的是案例是,MyBatis 利用 FactoryBean 来生产 Mapper 的代理对象(因为 Mapper 是一个接口)