缘起

在spring的常见面试题中,经常会被问及FactoryBean和BeanFactory的区别与联系。这两个类虽然长得很像,但是他们的作用确实完全不像。其实这二者本就并没有什么关系,要是一定要说说关系,那或者就是二者都是一个接口吧。但要是说区别却能说出一大堆


  • BeanFactory 以Factory结尾,表示它是一个工厂类,用于管理Bean的一个工厂,在Spring中,所有的Bean都是由BeanFactory(也就是IOC容器)来进行管理的。
  • FactoryBean 以Bean结尾,就是一个Bean,但这个Bean不是简单的Bean,而是一个能生产或者修饰对象生成的工厂Bean,实现这个接口的​​getObejct​​方法,就可以在此方法中返回一个Bean并放入Spring容器中。

BeanFactory

Spring中的FactoryBean和BeanFactory_spring

可以看到,对应BeanFactory来说,它的职责包括:实例化、定位、配置应用程序中的对象及建立这些对象间的依赖等等,反正就是对Bean的管理基本都靠他,但她是个接口,Spring容器给出了很多种实现,如 DefaultListableBeanFactory、XmlBeanFactory、ApplicationContext等。

FactoryBean

Spring中的FactoryBean和BeanFactory_ide_02

可以看到在该接口中定义了以下3个方法:


  • T getObject():返回由FactoryBean创建的Bean实例,如果isSingleton()返回true,则该实例会放到Spring容器中单实例缓存池中;
  • boolean isSingleton():返回由FactoryBean创建的Bean实例的作用域是singleton还是prototype;
  • Class getObjectType():返回FactoryBean创建的Bean类型。

那么这个类的使用场景是什么呢?一般情况下,Spring通过反射机制利用的class属性指定实现类实例化Bean,但这种实例化Bean的方式看起来似乎有点笨拙。我举一个简单的例子,比如你的项目里面需要根据一个参数来判定具体要实例化哪个Bean,Class A或者Class B. 那么你会怎么做呢?可能你会把这两个类都实例化出来,然后业务中根据参数来调用Class A or Class B。但更好的实现方式如下

public class C implements FactoryBean {

@Value("${icd.version}")
private String icdVersion;

@Override
public Object getObject() throws Exception {
if (xxx) {
return SpringManager.getBean(A.class);
} else{
return SpringManager.getBean(B.class);
}
}

@Override
public Class<?> getObjectType() {
//A和B的共同父类
return xxx.class;
}

@Override
public boolean isSingleton() {
return true;
}
}

SpringManager

@Component
public class SpringManager implements ApplicationContextAware {

private static ApplicationContext context = null;

@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
context = applicationContext;
}

public static ApplicationContext getApplicationContext() {
return context;
}

public static Object getBean(String name) {
return context.getBean(name);
}

public static <T> T getBean(Class<T> clazz) {
return context.getBean(clazz);
}
}

这样我们外面只需要用​​SpringManager.getBean(C)​​的方式就可以获取到Class A or Class B了,完美。