BeanFactory与FactoryBean的区别
最近和朋友探讨有关Spring源码的话题,就聊到了BeanFactory与FactoryBean的区别,这个问题也是我过往面试中被问到最多的关于Spring的面试题,今天就写下我的简单理解。
BeanFactory
我们先看看源码:
public interface BeanFactory{
String FACTORY_BEAN_PREFIX = "&";
Object getBean(String name) throws BeansException;
<T> T getBean(String name, Class<T> requiredType) throws BeansException;
Object getBean(String name, Object... args) throws BeansException;
<T> T getBean(Class<T> requiredType) throws BeansException;
<T> T getBean(Class<T> requiredType, Object... args) throws BeansException;
<T> ObjectProvider<T> getBeanProvider(Class<T> requiredType);
<T> ObjectProvider<T> getBeanProvider(ResolvableType requiredType);
boolean containsBean(String name);
boolean isSingleton(String name) throws NoSuchBeanDefinitionException;
boolean isPrototype(String name) throws NoSuchBeanDefinitionException;
boolean isTypeMatch(String name, ResolvableType typeToMatch) throws NoSuchBeanDefinitionException;
boolean isTypeMatch(String name, Class<?> typeToMatch) throws NoSuchBeanDefinitionException;
Class<?> getType(String name) throws NoSuchBeanDefinitionException;
String[] getAliases(String name);
}
以上是接口BeanFactory的源码,我们再来看看另外一张图:
这张图中的某些接口和类是不是很熟悉,具体的我们在后续Spring源码分析中介绍,给这张图的目的是想让大家知道一点,BeanFactory接口是顶层接口,它里面提供了IOC容器最基本的接口,也是SpringIOC最底层最基本的编程规范,但是它只是一个顶层接口,具体的IOC容器就是我上面这张图列举的,如DefaultListableBeanFactory、XmlBeanFactory、ApplicationContext等等,都是IOC容器的具体,具体分析也会在Spring源码解析中分析到。
FactoryBean
相比BeanFactory,FactoryBean的理解估计有些同学就有点模糊,那同样我们先看看源码:
public interface FactoryBean<T> {
T getObject() throws Exception;
Class<?> getObjectType();
default boolean isSingleton() {
return true;
}
}
FactoryBean中比较简单,就这3个方法,通过方法名我们大概也能猜出来这三个方法的含义:
T getObject():返回Bean的实例
Class<?> getObjectType():返回Bean实例的Type类型
boolean isSingleton():判断当前Bean是不是单例
我们先来看看实例:
public class TestFactoryBean implements FactoryBean<Person> {
}@Override
public Person getObject() throws Exception {
Person person = new Person();
person.setName("依痕梦");
person.setAge(18);
return person;
}
@Override
public Class<?> getObjectType() {
return Person.class;
}
@Override
public boolean isSingleton() {
return false;
}
Person中就两个最基本的属性,name和age,接下来我们看看xml:
<bean id="person" class="spring.ioc.test.bean.TestFactoryBean"/>
测试类:
@Test
public void test6(){
ApplicationContext context = new ClassPathXmlApplicationContext("Spring3.xml");
System.out.println("13:"+context.getBean("&person"));
System.out.println("14:"+context.getBean("person"));
System.out.println("15:"+context.getBean(Person.class));
}
执行结果:
13:spring.ioc.test.bean.TestFactoryBean@5c352895
14:Person{name='依痕梦', age=18}
15:Person{name='依痕梦', age=18}
BUILD SUCCESSFUL in 4s
当我们调用getBean(“person”)时,Spring 通过反射机制发现 TestFactoryBean 实现了 FactoryBean 的接口,这时 Spring 容器就调用接口方法 TestFactoryBean 的getObject() 方法返回。如果希望获取 TestFactoryBean 的实例,则需要在使用 getBean(beanName) 方法时在 beanName 前显示的加上 “&” 前缀。
相关源码:
org.springframework.beans.factory.support.AbstractBeanFactory#getObjectForBeanInstance
// 普通bean和factoryBean的判断
bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);
org.springframework.beans.factory.support.FactoryBeanRegistrySupport#getObjectFromFactoryBean
object = getObjectFromFactoryBean(factory, beanName, !synthetic);
org.springframework.beans.factory.support.FactoryBeanRegistrySupport#doGetObjectFromFactoryBean
Object object = doGetObjectFromFactoryBean(factory, beanName);
private Object doGetObjectFromFactoryBean(final FactoryBean<?> factory, final String beanName)
throws BeanCreationException {
Object object;
try {
if (System.getSecurityManager() != null) {
AccessControlContext acc = getAccessControlContext();
try {
object = AccessController.doPrivileged((PrivilegedExceptionAction<Object>) factory::getObject, acc);
}
catch (PrivilegedActionException pae) {
throw pae.getException();
}
}
else {
object = factory.getObject();//这里就是调用FactoryBean实现类的getObject()
}
}
catch (FactoryBeanNotInitializedException ex) {
throw new BeanCurrentlyInCreationException(beanName, ex.toString());
}
catch (Throwable ex) {
throw new BeanCreationException(beanName, "FactoryBean threw exception on object creation", ex);
}
// Do not accept a null value for a FactoryBean that's not fully
// initialized yet: Many FactoryBeans just return null then.
if (object == null) {
if (isSingletonCurrentlyInCreation(beanName)) {
throw new BeanCurrentlyInCreationException(
beanName, "FactoryBean which is currently in creation returned null from getObject");
}
object = new NullBean();
}
return object;
}
以上就源码调用的大致过程,希望对大家有所帮助。
总结
其实,看到这里,大致上也清楚的这两者的区别,BeanFactory是个Factory,也就是我们常理解的IOC容器,而FactoryBean是个Bean,IOC容器就是来管理Bean的。其实在Spring中存在两种Bean,一种是基础Bean,另一种就是FactoryBean,是个特殊的Bean,通过上面的分析我们可以看出FactoryBean是可以生产或者修饰对象的工厂Bean,Spring本身就提供了几十种FactoryBean的实现,有兴趣的小伙伴也可以自己去研究。好了,区别大概就是这样了,这是我自己的理解,大家也可以提出自己的理解,我们一起相互讨论。