Spring中BeanFactory与FactoryBean的区别

在Spring中有BeanFactory和FactoryBean这2个接口,从名字来看很类似,比较容易搞混。html

1、BeanFactory

BeanFactory是一个接口,它是Spring中工厂的顶层规范,是SpringIoc容器的核心接口,它定义了getBean()containsBean()等管理Bean的通用方法。Spring的容器都是它的具体实现如:java

  • DefaultListableBeanFactoryspring

  • XmlBeanFactory设计模式

  • ApplicationContext安全

这些实现类又从不一样的维度分别有不一样的扩展。ide

1.一、源码

public interface BeanFactory {

	//对FactoryBean的转义定义,由于若是使用bean的名字检索FactoryBean获得的对象是工厂生成的对象,
	//若是须要获得工厂自己,须要转义
	String FACTORY_BEAN_PREFIX = "&";

	//根据bean的名字,获取在IOC容器中获得bean实例
	Object getBean(String name) throws BeansException;

	//根据bean的名字和Class类型来获得bean实例,增长了类型安全验证机制。
	<T> T getBean(String name, @Nullable 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;

	//提供对bean的检索,看看是否在IOC容器有这个名字的bean
	boolean containsBean(String name);

	//根据bean名字获得bean实例,并同时判断这个bean是否是单例
	boolean isSingleton(String name) throws NoSuchBeanDefinitionException;

	boolean isPrototype(String name) throws NoSuchBeanDefinitionException;

	boolean isTypeMatch(String name, ResolvableType typeToMatch) throws NoSuchBeanDefinitionException;

	boolean isTypeMatch(String name, @Nullable Class<?> typeToMatch) throws NoSuchBeanDefinitionException;

	//获得bean实例的Class类型
	@Nullable
	Class<?> getType(String name) throws NoSuchBeanDefinitionException;

	//获得bean的别名,若是根据别名检索,那么其原名也会被检索出来
	String[] getAliases(String name);
}

1.一、使用场景

  • 从Ioc容器中获取Bean(byName or byType)
  • 检索Ioc容器中是否包含指定的Bean
  • 判断Bean是否为单例

2、FactoryBean

首先它是一个Bean,但又不只仅是一个Bean。它是一个能生产或修饰对象生成的工厂Bean,相似于设计模式中的工厂模式和装饰器模式。它能在须要的时候生产一个对象,且不只仅限于它自身,它能返回任何Bean的实例。测试

2.一、源码

public interface FactoryBean<T> {

	//从工厂中获取bean
	@Nullable
	T getObject() throws Exception;

	//获取Bean工厂建立的对象的类型
	@Nullable
	Class<?> getObjectType();

	//Bean工厂建立的对象是不是单例模式
	default boolean isSingleton() {
		return true;
	}
}

从它定义的接口能够看出,FactoryBean表现的是一个工厂的职责。 即一个Bean A若是实现了FactoryBean接口,那么A就变成了一个工厂,根据A的名称获取到的其实是工厂调用getObject()返回的对象,而不是A自己,若是要获取工厂A自身的实例,那么须要在名称前面加上'&'符号。ui

  • getObject('name')返回工厂中的实例
  • getObject('&name')返回工厂自己的实例

一般状况下,bean 无须本身实现工厂模式,Spring 容器担任了工厂的 角色;但少数状况下,容器中的 bean 自己就是工厂,做用是产生其余 bean 实例。由工厂 bean 产生的其余 bean 实例,再也不由 Spring 容器产生,所以与普通 bean 的配置不一样,再也不须要提供 class 元素。this

2.二、示例

先定义一个Bean实现FactoryBean接口设计

@Component
public class MyBean implements FactoryBean {
    private String message;
    public MyBean() {
        this.message = "经过构造方法初始化实例";
    }
    @Override
    public Object getObject() throws Exception {
        // 这里并不必定要返回MyBean自身的实例,能够是其余任何对象的实例。
        //如return new Student()...
        return new MyBean("经过FactoryBean.getObject()建立实例");
    }
    @Override
    public Class<?> getObjectType() {
        return MyBean.class;
    }
    public String getMessage() {
        return message;
    }
}

MyBean实现了FactoryBean接口的两个方法,getObject()是能够返回任何对象的实例的,这里测试就返回MyBean自身实例,且返回前给message字段赋值。同时在构造方法中也为message赋值。而后测试代码中先经过名称获取Bean实例,打印message的内容,再经过&+名称获取实例并打印message内容。

@RunWith(SpringRunner.class)
@SpringBootTest(classes = TestApplication.class)
public class FactoryBeanTest {
    @Autowired
    private ApplicationContext context;
    @Test
    public void test() {
        MyBean myBean1 = (MyBean) context.getBean("myBean");
        System.out.println("myBean1 = " + myBean1.getMessage());
        MyBean myBean2 = (MyBean) context.getBean("&myBean");
        System.out.println("myBean2 = " + myBean2.getMessage());
        System.out.println("myBean1.equals(myBean2) = " + myBean1.equals(myBean2));
    }
}
myBean1 = 经过FactoryBean.getObject()初始化实例
myBean2 = 经过构造方法初始化实例
myBean1.equals(myBean2) = false

2.三、使用场景

说了这么多,为何要有FactoryBean这个东西呢,有什么具体的做用吗?
FactoryBean在Spring中最为典型的一个应用就是用来建立AOP的代理对象

咱们知道AOP其实是Spring在运行时建立了一个代理对象,也就是说这个对象,是咱们在运行时建立的,而不是一开始就定义好的,这很符合工厂方法模式。更形象地说,AOP代理对象经过Java的反射机制,在运行时建立了一个代理对象,在代理对象的目标方法中根据业务要求织入了相应的方法。这个对象在Spring中就是——ProxyFactoryBean

因此,FactoryBean为咱们实例化Bean提供了一个更为灵活的方式,咱们能够经过FactoryBean建立出更为复杂的Bean实例。

3、区别

  • 他们两个都是个工厂,但FactoryBean本质上仍是一个Bean,也归BeanFactory管理
  • BeanFactory是Spring容器的顶层接口,FactoryBean更相似于用户自定义的工厂接口。
总结

BeanFactoryFactoryBean的区别确实容易混淆,死记硬背是不行的,最好仍是从源码层面,置于spring的环境中去理解。

参考:
http://www.javashuo.com/article/p-effjodgv-hn.html
http://www.javashuo.com/article/p-dqgqwprp-cv.html

相关文章
相关标签/搜索