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

一、BeanFactory

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

  • DefaultListableBeanFactory
  • XmlBeanFactory
  • ApplicationContext

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

1.1 BenaFactory源码

  1. public interface BeanFactory {
  2.  
  3. /**
  4. * 用来获得实例的引用,并且区分FactoryBean区分。
  5. * 如果使用bean的名字myJndiObject获取FactoryBean,返回的是一个工厂,而不是工厂的实例;如果需要获得工厂实例,需要转义。
    */
  6. String FACTORY_BEAN_PREFIX = "&";
  7.  
  8. /**
  9. * 根据bean的名称,获取指定的bean实例,该实例可以是共享的,也可以是独立的.
    */
  10. Object getBean(String name) throws BeansException;
  11.  
  12. /**
  13. * 根据bean的名称,获取指定的bean实例,该实例可以是共享的,也可以是独立的.并且增加了一个类型的检验。
    */
  14. <T> T getBean(String name, Class<T> requiredType) throws BeansException;
  15.  
  16. Object getBean(String name, Object... args) throws BeansException;
  17.  
  18. /**
  19. * 根据给定类型返回匹配的bean实例.
    */
  20. <T> T getBean(Class<T> requiredType) throws BeansException;
  21.  
  22. <T> T getBean(Class<T> requiredType, Object... args) throws BeansException;
  23.  
  24. /**
  25. * 检查spring的bean容器中是否包含有该bean
    */
  26. boolean containsBean(String name);
  27.  
  28. /**
  29. * 判断bean的作用域是否是singleton
    */
  30. boolean isSingleton(String name) throws NoSuchBeanDefinitionException;
  31.  
  32. /**
  33. * 判断bena的作用域是否是prototype
    */
  34. boolean isPrototype(String name) throws NoSuchBeanDefinitionException;
  35.  
  36. /**
  37. * 检查给定名称的bean是否和指定类型匹配.更确却的说是通过检查给定的bean,返回指定类型的目标对象
    */
  38. boolean isTypeMatch(String name, ResolvableType typeToMatch) throws NoSuchBeanDefinitionException;
  39.  
  40. boolean isTypeMatch(String name, Class<?> typeToMatch) throws NoSuchBeanDefinitionException;
  41.  
  42. /**
  43. * 获取给定名称的bean的class类型
    */
  44. Class<?> getType(String name) throws NoSuchBeanDefinitionException;
  45.  
  46. /**
  47. * 获取给定bean名称的别名,如果根据别名检索,将会获得原始bean名称。
  48. *
  49. String[] getAliases(String name);
  50.  
  51. }

1.2 使用场景

  • 从Ioc容器中获取Bean(byName or byType):context.getBean("father", Father.class)、context.getBean("father")
  • 检索Ioc容器中是否包含指定的Bean:  context.containsBean("father")
  • 判断Bean是否为单例:  context.isSingleton("father")

二、FactoryBean

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

2.1 FactoryBean源码

  1. public interface FactoryBean<T> {
  2.  
  3. /**
  4. * 从工厂中获取bean实例
  5. */
  6. T getObject() throws Exception;
  7.  
  8. /**
  9. * 从工厂中获取bean实例对象的类型
  10. */
  11. Class<?> getObjectType();
  12.  
  13. /**
  14. * 工厂创建的对象是否是单例
  15. */
  16. boolean isSingleton();
  17.  
  18. }

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

  • getObject('name')返回工厂中的实例
  • getObject('&name')返回工厂本身的实例

通常情况下,bean 无须自己实现工厂模式,Spring 容器担任了工厂的 角色;但少数情况下,容器中的 bean 本身就是工厂,作用是产生其他 bean 实例。由工厂 bean 产生的其他 bean 实例,不再由 Spring 容器产生,因此与普通 bean 的配置不同,不再需要提供 class 元素。

2.2 示例

先定义一个Bean实现FactoryBean接口:

  1. @Component
  2. public class MyBean implements FactoryBean {
  3. private String message;
  4. public MyBean() {
  5. this.message = "通过构造方法初始化实例";
  6. }
  7.  
  8. public MyBean(String message) {
  9. this.message = message;
  10. }
  11.  
  12. @Override
  13. public Object getObject() throws Exception {
  14. // 这里并不一定要返回MyBean自身的实例,可以是其他任何对象的实例
  15. return new MyBean("通过FactoryBean.getObject()创建实例");
  16. }
  17. @Override
  18. public Class<?> getObjectType() {
  19. return MyBean.class;
  20. }
  21. public String getMessage() {
  22. return message;
  23. }
  24.  
  25. @Override
  26. public boolean isSingleton() {
  27. return false;
  28. }
  29. }

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

  1. @RunWith(SpringRunner.class)
  2. @SpringBootTest(classes = HelloApplication.class)
  3. public class FactoryBeanTest {
  4. @Autowired
  5. private ApplicationContext context;
  6. @Test
  7. public void test() {
  8. MyBean myBean1 = (MyBean) context.getBean("myBean");//返回工厂中的实例,调用FactoryBean.getObject()创建实例
  9. System.out.println("myBean1 = " + myBean1.getMessage());
  10. MyBean myBean2 = (MyBean) context.getBean("&myBean");//返回工厂本身,通过构造方法初始化实例
  11. System.out.println("myBean2 = " + myBean2.getMessage());
  12. System.out.println("myBean1.equals(myBean2) = " + myBean1.equals(myBean2));
  13. }
  14. }

打印结果:

  1. myBean1 = 通过FactoryBean.getObject()创建实例
  2. myBean2 = 通过构造方法初始化实例
  3. myBean1.equals(myBean2) = false

2.3 使用场景

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

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

所以,FactoryBean为我们实例化Bean提供了一个更为灵活的方式,我们可以通过FactoryBean创建出更为复杂的Bean实例。

三、区别

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

参考: Spring中BeanFactory与FactoryBean的区别

Spring中BeanFactory与FactoryBean的区别的更多相关文章

  1. 【Java面试】Spring中 BeanFactory和FactoryBean的区别

    一个工作了六年多的粉丝,胸有成竹的去京东面试. 然后被Spring里面的一个问题卡住,唉,我和他说,6年啦,Spring都没搞明白? 那怎么去让面试官给你通过呢? 这个问题是: Spring中Bean ...

  2. spring中BeanFactory和FactoryBean的区别

    共同点: 都是接口 区别: BeanFactory 以Factory结尾,表示它是一个工厂类,用于管理Bean的一个工厂 在Spring中,所有的Bean都是由BeanFactory(也就是IOC容器 ...

  3. Spring中BeanFactory与FactoryBean到底有什么区别?

    一.BeanFactory BeanFactory是一个接口,它是Spring中工厂的顶层规范,是SpringIoc容器的核心接口,它定义了getBean().containsBean()等管理Bea ...

  4. Spring中BeanFactory与ApplicationContext的区别

    BeanFactory:Bean工厂接口,是访问Spring Bean容器的根接口,基本Bean视图客户端.从其名称上即可看出其功能,即实现Spring Bean容器的读取. ApplicationC ...

  5. Spring中BeanFactory和ApplicationContext的区别

    1. BeanFactory负责读取bean配置文档,管理bean的加载,实例化,维护bean之间的依赖关系,负责bean的生命周期. 2. ApplicationContext除了提供上述BeanF ...

  6. BeanFactory 和FactoryBean的区别

    转自:https://www.cnblogs.com/aspirant/p/9082858.html BeanFacotry是spring中比较原始的Factory.如XMLBeanFactory就是 ...

  7. Spring BeanFactory与FactoryBean的区别及其各自的详细介绍于用法

    Spring BeanFactory与FactoryBean的区别及其各自的详细介绍于用法 1. BeanFactory BeanFactory,以Factory结尾,表示它是一个工厂类(接口),用于 ...

  8. BeanFactory和FactoryBean的区别

    转自:http://blog.csdn.net/wangbiao007/article/details/53183764 1.BeanFactory BeanFactory是IOC最基本的容器,负责生 ...

  9. 转:BeanFactory和FactoryBean的区别

    一.BeanFactory简介 BeanFacotry是spring中比较原始的Factory.如XMLBeanFactory就是一种典型的BeanFactory.原始的BeanFactory无法支持 ...

随机推荐

  1. win10安装ubuntu双系统遇到的问题

    安装过程学习了几个博客 Ubuntu 16.04与Win10双系统双硬盘安装图解:https://www.cnblogs.com/coxiseed/p/9945202.html?tdsourcetag ...

  2. docker port is already allocated 的解决方案

    ps -aux | grep -v grep | grep docker-proxy 第二列为进程号 停止 doker 进程,删除所有容器,然后删除 local-kv.db 这个文件,再启动 dock ...

  3. odoo开发笔记 -- 当前时间&时间运算相关

    当前日期/时间: from datetime import datetime, timedelta now_time = datetime.now() today_date_format = now_ ...

  4. 工具推荐--Mac下画图软件:Omnigraffle

    场景描述: 日常工作中,开发的小伙伴可能会遇到,需要画流程图,架构图,时序图,UML图,网络拓扑图...等等各种图,有的小伙伴用Visio,ProcessOn,亿图图示......又是一堆软件,先不说 ...

  5. jstl标签库使用报错index_jsp.java找不到问题

    初学jstl的时候记得只需要讲jstl和standard的jar放在lib下面,然后jsp中使用对应导入语法就可以使用标签库了. 但那时候用的是myeclipes,myeclipes的导包的过程记得是 ...

  6. scrapy中的middleware

    反反爬虫相关机制 Some websites implement certain measures to prevent bots from crawling them, with varying d ...

  7. linux安装redis时报collect2: fatal error: cannot find 'ld'和In file included from adlist.c:34:0:

    如题,看了下该ld命令所在文件: [root@centos redis-]# whereis ld ld: /usr/bin/ld.gold /usr/bin/ld /usr/bin/ld.bfd / ...

  8. 为什么java里面经常作List判断的时候,既要判断list不为null,又要判断size>0呢?

    没有考虑到具体的问题上面,我们单纯的来讲: 为什么java里面经常作List判断的时候,既要判断list不为null,又要判断size>0呢? list == null 说明list没有初始化( ...

  9. a simple machine learning system demo, for ML study.

    Machine Learning System introduction This project is a full stack Django/React/Redux app that uses t ...

  10. TensorFlow 8 bit模型量化

    本文基本参考自这篇文章:8-Bit Quantization and TensorFlow Lite: Speeding up mobile inference with low precision ...