Spring 中 BeanFactory 与 FactoryBean 的区别
Posted 琦彦
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Spring 中 BeanFactory 与 FactoryBean 的区别相关的知识,希望对你有一定的参考价值。
Spring 中 BeanFactory 与 FactoryBean 的区别
直接区别
直面意思:Bean工厂、工厂Bean
1、BeanFactory:以 Factory 结尾,表示它是一个工厂类(接口),用于管理 Bean 的一个工厂。在 Spring 中,BeanFactory 是 IOC 容器的核心接口,它的职责包括:实例化、定位、配置应用程序中的对象及建立这些对象间的依赖。
2、FactoryBean:以 Bean 结尾,表示它是一个 Bean,不同于普通 Bean 的是:它是实现了 FactoryBean<T>
接口的 Bean,通过该 Bean 的 ID 从 BeanFactory 中获取的实际上是 FactoryBean 的 getObject()
返回的对象,而不是 FactoryBean 本身,如果要获取 FactoryBean 对象,请在 id 前面加一个 &
符号来获取。
BeanFactory 是什么?
BeanFactory,以 Factory 结尾,表示它是一个工厂类(接口),用于管理 Bean 的一个工厂。在 Spring 中,BeanFactory 是IOC容器的核心接口,它的职责包括:实例化、定位、配置应用程序中的对象及建立这些对象间的依赖。
BeanFactory 是一个接口,它是 Spring 中工厂的顶层规范,是 SpringIoc 容器的核心接口,它定义了 getBean()
、containsBean()
等管理 Bean 的通用方法。
Spring 的容器都是它的具体实现如:
- DefaultListableBeanFactory
- XmlBeanFactory
- ApplicationContext
这些实现类又从不同的维度分别有不同的扩展。
例如 XmlBeanFactory 类将持有此 XML 配置元数据,并用它来构建一个完全可配置的系统或应用,如下实例化容器
Resource resource = new FileSystemResource("beans.xml");
BeanFactory factory = new XmlBeanFactory(resource);
ClassPathResource resource = new ClassPathResource("beans.xml");
BeanFactory factory = new XmlBeanFactory(resource);
ApplicationContext context =
new ClassPathXmlApplicationContext(new String[] "applicationContext.xml", "applicationContext-part2.xml");
BeanFactory factory = (BeanFactory) context;
BeanFactory 接口解读
下面介绍一下这个核心接口的内容
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);
这个 BeanFactory 使用场景
1、从 Ioc 容器中获取 Bean(byName or byType)
2、检索 Ioc 容器中是否包含指定的 Bean
3、判断 Bean 是否为单例
FactoryBean 是什么?
一般情况下,Spring 通过反射机制利用 <bean>
的 class 属性指定实现类实例化 Bean,在某些情况下,实例化 Bean 过程比较复杂,如果按照传统的方式,则需要在 <bean>
中提供大量的配置信息。
因为配置方式的灵活性是受限的,这时采用编码的方式反而可能更快,这样就违背了 Spring 的意图了,所以 Spring 为此提供了一个 FactoryBean 的工厂类接口,用户可以通过实现该接口定制实例化 Bean 的逻辑。
第三方框架要继承进 Spring,往往就是通过实现 FactoryBean 来集成的。比如 MyBatis 的 SqlSessionFactoryBean、RedisRepositoryFactoryBean、EhCacheManagerFactoryBean 等等
实现了这个 FactoryBean 接口的类,它只是一个 Bean,它是一个生产或修饰对象生成的工厂 Bean,类似于设计模式中的工厂模式和装饰器模式。
它能生产一个对象,且不仅仅限于它自身,它能返回任何 Bean 的实例。
补充:FactoryBean 接口对于 Spring 框架来说占用重要的地位,Spring自身就提供了70多个 FactoryBean 的实现。
这个接口如下所示:
public interface FactoryBean<T>
//从工厂中获取bean
@Nullable
T getObject() throws Exception;
//获取Bean工厂创建的对象的类型
@Nullable
Class<?> getObjectType();
//Bean工厂创建的对象是否是单例模式
default boolean isSingleton()
return true;
从 FactoryBean 定义的接口可以看出,FactoryBean 表现的是一个工厂的职责。 即一个 Bean A 如果实现了 FactoryBean 接口,那么 A 就变成了一个工厂,根据 A 的名称获取到的实际上是工厂调用 getObject()
返回的对象,而不是 A 本身,如果要获取工厂 A 自身的实例,那么需要在名称前面加上 '&'
符号。
getObject('name')
返回工厂中的实例getObject('&name')
返回工厂本身的实例
注意:通常情况下,bean 无须自己实现工厂模式,Spring 容器担任了工厂的角色;但少数情况下,容器中的 bean 本身就是工厂,作用是产生其他 bean 实例。
补充:在 Bean 循环依赖三级缓存中可以看到:
/** 三级级缓存:存放 bean 工厂对象,用于解决循环依赖 */
private final Map<String, ObjectFactory<?>> singletonFactories =
new HashMap<>(16);
它是做第三级缓存的
FactoryBean 使用场景
说了这么多,为什么要有 FactoryBean 这个东西呢,有什么具体的作用吗?
FactoryBean 在 Spring 中最为典型的一个应用就是用来 创建 AOP 的代理对象。
我们知道 AOP 实际上是 Spring 在运行时创建了一个代理对象,也就是说这个对象,是我们在运行时创建的,而不是一开始就定义好的,这很符合工厂方法模式。
更形象地说,AOP 代理对象通过 Java的反射机制,在运行时创建了一个代理对象,在代理对象的目标方法中根据业务要求织入了相应的方法。这个对象在 Spring 中就是——ProxyFactoryBean。
所以,FactoryBean 为我们实例化 Bean 提供了一个更为灵活的方式,我们可以通过 FactoryBean 创建出更为复杂的 Bean 实例。
使用示例
注意:一般 Spring 内置的 FactoryBean 就足够使用了,这里只是为了演示如何自定义 FactoryBean
先定义一个 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 内容。
编写一个测试类,使用这个自定义的 FactoryBean
@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));
打印结果
Code
myBean1 = 通过FactoryBean.getObject()初始化实例
myBean2 = 通过构造方法初始化实例
myBean1.equals(myBean2) = false
它们两个的区别
BeanFacotry 是 Spring 中比较原始的 Factory。如 XMLBeanFactory 就是一种典型的BeanFactory。
而常用的 ApplicationContext 接口,它就由 BeanFactory 接口派生而来,ApplicationContext 包含 BeanFactory 的所有功能,通常建议比 BeanFactory 优先
原始的 BeanFactory 无法支持 Spring 的许多插件,如 AOP 功能、Web 应用等。
即他们两个都是个工厂,但 FactoryBean 本质上还是一个 Bean,也归 BeanFactory 管理,而 BeanFactory 是 Spring 容器的顶层接口,FactoryBean 更类似于用户自定义的工厂接口。
总结:
BeanFactory 是接口,提供了 IOC 容器最基本的形式,给具体的 IOC 容器的实现提供了规范,
FactoryBean 也是接口,为 IOC 容器中 Bean 的实现提供了更加灵活的方式,FactoryBean在 IOC 容器的基础上给 Bean 的实现加上了一个简单工厂模式和装饰模式,我们可以在 getObject()
方法中灵活配置。
Reference
【小家Spring】一文读懂Spring中的BeanFactory和FactoryBean(以及它和ObjectFactory的区别)的区别
Spring中BeanFactory与FactoryBean的区别
掌握Spring中的beanfactory与factorybean有什么好处?
https://alsritter.icu/posts/beed7112/
以上是关于Spring 中 BeanFactory 与 FactoryBean 的区别的主要内容,如果未能解决你的问题,请参考以下文章
spring中ApplicationContext与BeanFactory容器的区别
Spring中BeanFactory与FactoryBean的区别
Spring中ApplicationContext与BeanFactory容器的区别
Spring BeanFactory与FactoryBean的区别及其各自的详细介绍于用法