你所不知道的BeanFactory与FactoryBean的区别

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的实现,有兴趣的小伙伴也可以自己去研究。好了,区别大概就是这样了,这是我自己的理解,大家也可以提出自己的理解,我们一起相互讨论。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值