简单了解Spring中BeanFactory与FactoryBean的区别

 更新时间:2019年12月24日 10:13:09   作者:何其有静  
这篇文章主要介绍了简单了解Spring中BeanFactory与FactoryBean的区别,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下

这篇文章主要介绍了简单了解Spring中BeanFactory与FactoryBean的区别,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下

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

一、BeanFactory

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

  • DefaultListableBeanFactory
  • XmlBeanFactory
  • ApplicationContext

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

1.1 BenaFactory源码

public interface BeanFactory {

  /**
   * 用来获得实例的引用,并且区分FactoryBean区分。
   * 如果使用bean的名字myJndiObject获取FactoryBean,返回的是一个工厂,而不是工厂的实例;如果需要获得工厂实例,需要转义。
   */
  String FACTORY_BEAN_PREFIX = "&";

  /**
   * 根据bean的名称,获取指定的bean实例,该实例可以是共享的,也可以是独立的.
   */
  Object getBean(String name) throws BeansException;

  /**
   * 根据bean的名称,获取指定的bean实例,该实例可以是共享的,也可以是独立的.并且增加了一个类型的检验。
   */
  <T> T getBean(String name, Class<T> requiredType) throws BeansException;

  Object getBean(String name, Object... args) throws BeansException;

  /**
   * 根据给定类型返回匹配的bean实例.
   */
  <T> T getBean(Class<T> requiredType) throws BeansException;

  <T> T getBean(Class<T> requiredType, Object... args) throws BeansException;

  /**
   * 检查spring的bean容器中是否包含有该bean
   */
  boolean containsBean(String name);

  /**
   * 判断bean的作用域是否是singleton
   */
  boolean isSingleton(String name) throws NoSuchBeanDefinitionException;

  /**
   * 判断bena的作用域是否是prototype
   */
  boolean isPrototype(String name) throws NoSuchBeanDefinitionException;

  /**
   * 检查给定名称的bean是否和指定类型匹配.更确却的说是通过检查给定的bean,返回指定类型的目标对象
   */
  boolean isTypeMatch(String name, ResolvableType typeToMatch) throws NoSuchBeanDefinitionException;

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

  /**
   * 获取给定名称的bean的class类型
   */
  Class<?> getType(String name) throws NoSuchBeanDefinitionException;

  /**
   * 获取给定bean名称的别名,如果根据别名检索,将会获得原始bean名称。
   * 
  String[] getAliases(String name);

}

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源码

public interface FactoryBean<T> {

  /**
   * 从工厂中获取bean实例
   */
  T getObject() throws Exception;

  /**
   * 从工厂中获取bean实例对象的类型
   */
  Class<?> getObjectType();

  /**
   * 工厂创建的对象是否是单例
   */
  boolean isSingleton();

}

从它定义的接口可以看出,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接口:

@Component
public class MyBean implements FactoryBean {
  private String message;
  public MyBean() {
    this.message = "通过构造方法初始化实例";
  }

  public MyBean(String message) {
    this.message = message;
  }

  @Override
  public Object getObject() throws Exception {
    // 这里并不一定要返回MyBean自身的实例,可以是其他任何对象的实例
    return new MyBean("通过FactoryBean.getObject()创建实例");
  }
  @Override
  public Class<?> getObjectType() {
    return MyBean.class;
  }
  public String getMessage() {
    return message;
  }

  @Override
  public boolean isSingleton() {
    return false;
  }
}

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

@RunWith(SpringRunner.class)
@SpringBootTest(classes = HelloApplication.class)
public class FactoryBeanTest {
  @Autowired
  private ApplicationContext context;
  @Test
  public void test() {
    MyBean myBean1 = (MyBean) context.getBean("myBean");//返回工厂中的实例,调用FactoryBean.getObject()创建实例
    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.3 使用场景

说了这么多,为什么要有FactoryBean这个东西呢,有什么具体的作用吗?

FactoryBean在Spring中最为典型的一个应用就是用来创建AOP的代理对象。

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

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

三、区别

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

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持脚本之家。

相关文章

  • HTTP中get和post的区别详解

    HTTP中get和post的区别详解

    这篇文章主要为大家详细介绍了HTTP中get和post的区别,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2017-08-08
  • javaweb实战之商城项目开发(三)

    javaweb实战之商城项目开发(三)

    这篇文章主要针对javaweb商城项目开发进行实战演习,主要实现通用的BaseDao.java和使用resultMap映射关联对象,感兴趣的小伙伴们可以参考一下
    2016-02-02
  • JavaWeb实现裁剪图片上传完整代码

    JavaWeb实现裁剪图片上传完整代码

    这篇文章主要为大家详细介绍了javaWeb实现裁剪图片上传完整代码,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2016-09-09
  • Java中WeakHashMap的使用详解

    Java中WeakHashMap的使用详解

    这篇文章主要介绍了Java中WeakHashMap的使用详解,WeakHashMap是一种弱引用的Map,底层数据结构为数组链表,与HashMap相比,WeakHashMap的区别在于它的key存储为弱引用,在垃圾回收时,如果key没有被强引用所引用,那么key会被回收掉,需要的朋友可以参考下
    2023-09-09
  • Java 十进制转二、八、十六进制的字符串

    Java 十进制转二、八、十六进制的字符串

    本文主要介绍了十进制转二进制;十进制转八进制;十进制转十六进制的方法,具有很好的参考价值,下面跟着小编一起来看下吧
    2017-02-02
  • 详解用Eclipse如何创建Web项目

    详解用Eclipse如何创建Web项目

    本篇文章主要介绍了详解用Eclipse如何创建Web项目,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2017-12-12
  • java selenium操作弹出对话框示例讲解

    java selenium操作弹出对话框示例讲解

    本文主要介绍java selenium操作弹出对话框,这里给大家整理了相关资料,并附示例代码和实现效果图,有兴趣的小伙伴可以参考下
    2016-08-08
  • springboot封装响应实体的实例代码

    springboot封装响应实体的实例代码

    这篇文章主要介绍了springboot封装响应实体,本文通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2023-07-07
  • 处理java异步事件的阻塞和非阻塞方法分析

    处理java异步事件的阻塞和非阻塞方法分析

    这篇文章主要介绍了处理java异步事件的阻塞和非阻塞方法分析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,阻塞与非阻塞关注的是交互双方是否可以弹性工作。,需要的朋友可以参考下
    2019-06-06
  • java实现对Hadoop的操作

    java实现对Hadoop的操作

    这篇文章主要介绍了java实现对Hadoop的操作,通过非常完整详细的代码展示了如何去进行一系列操作,包括基本操作,文件读写,需要的朋友可以参考下
    2021-07-07

最新评论