Spring5源码分析(022)——IoC篇之bean加载:FactoryBean的用法

注:《Spring5源码分析》汇总可参考:Spring5源码分析(002)——博客汇总


  上一篇主要是粗略地分析了 Spring 加载 bean 的整个过程,并没有太多细致的解析,而其中前面几个处理步骤中则反复提及到了 FactoryBean ,本篇将就此小知识进行讲解,目录结构如下:

1、FactoryBean 的用法

  一般情况下,Spring 是通过反射机制利用 bean 的 class 属性指定的实现类来实例化 bean 的。在某些情况下,实例化 bean 过程比较复杂,如果按照传统的方式,则需要在 bean 中提供大量的配置信息,配置方式的灵活性是受限的,这时候采用编码的方式可能会得到一个简单的方案(当然如果有大量这样的处理的话,灵活性也同样有限,当作是一种补充就行)。Spring 为此提供了一个 org.springframework.beans.factory.FactoryBean 的工厂类接口,用户可以通过实现该接口定制实例化 bean 的逻辑。

  FactoryBean 接口对于 Spring 框架来说占有重要的地位, Spring 本身就提供了70多个 FactoryBean 实现类。他们隐藏了实例化一些复杂 bean 的细节,给上层应用带来了便利。从 Spring3.0 开始, FactoryBean 开始支持泛型,即接口声明改为 FactoryBean<T> 的形式:

public interface FactoryBean<T> {

    T getObject() throws Exception;

    Class<?> getObjectType();

    default boolean isSingleton() {
        return true;
    }

}

  该接口中定义了3个方法:

  • T getObject()
    • 返回由 FactoryBean 创建的 bean 实例,如果 isSingleton() 返回 true ,则该实例会放到 Spring 容器的单例缓存池中。
  • Class<?> getObjectType()
    • 返回 FactoryBean 创建的 bean 类型
  • boolean isSingleton()
    • 返回由 FactoryBean 创建的 bean 实例的作用域是 singleton 还是 prototype ,默认是单例 singleton ,即返回 true 。

  当配置文件中 <bean> 的 class 属性配置的实现类是 FactoryBean 时,通过 getBean() 方法返回的不是 FactoryBean 本身,而是 FactoryBean#getObject() 方法所返回的对象,相当于代理了 getBean() 方法。例如,如果使用传统方式配置下面的 Car 的 <bean> 时,Car 的每个属性则需要分别对应一个 <property> 元素标签:

public class Car {
    private int maxSpeed;
    private String brand;
    private double price;
    // setter and getter ...
}

  如果使用的是 FactoryBean 的方式来实现,则可以灵活配置,例如下面通过逗号分隔符的方式一次性地为 Car 的所有属性指定配置值:

public class CarFactoryBean implements FactoryBean<Car> {

   private String carInfo;

   @Override
   public Car getObject() throws Exception {
      Car car = new Car();
      String[] infos = carInfo.split(",");
      car.setBrand(infos[0]);
      car.setMaxSpeed(Integer.valueOf(infos[1]));
      car.setPrice(Double.valueOf(infos[2]));
      return car;
   }

   @Override
   public Class<Car> getObjectType() {
      return Car.class;
   }

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

   public String getCarInfo() {
      return this.carInfo;
   }

   // 接收逗号分隔符设置属性信息
   public void setCarInfo(String carInfo) {
      this.carInfo = carInfo;
   }
} 

  有了这个 CarFactoryBean 之后,就可以在配置文件中使用下面这种自定义的配置方式了:

<bean id="carBean" class="cn.wpbxin.bean.CarFactoryBean">
    <property name="carInfo" value="超跑,400,2000000" />
</bean>

  当调用 getBean("carBean") 时,Spring 通过反射机制发现 CarFactoryBean 实现了 FactoryBean 的接口,这时 Spring 容器就调用接口方法 CarFactoryBean#getObject() 方法返回。如果希望获取 CarFactoryBean 实例,则需要在使用 getBean(beanName) 时在 beanName 签加上 “&” 前缀,例如 getBean("&carBean"),表示需要获取 FactoryBean 实例本身,也就是 CarFactoryBean 本身。

2、参考

原文地址:https://www.cnblogs.com/wpbxin/p/14903163.html