Spring源码分析FactoryBean的使用
Posted wuxiaofeng
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Spring源码分析FactoryBean的使用相关的知识,希望对你有一定的参考价值。
摘要:本文结合《Spring源码深度解析》来分析Spring 5.0.6版本的源代码。若有描述错误之处,欢迎指正。
一般情况下,Spring通过反射机制利用bean的class属性指定实现类来实例化bean。在某些情况下,实例化bean过程比较复杂,如果按照传统的方式,则需要在<bean>中提供大量 的配置信息,配置方式的灵活性是受限的,这时采用编码的方式可能会得到一个简单的方案。 Spring 为此提供了一个org.springframework.beans.factory.FactoryBean的工厂类接口,用户可以通过实现该接口定制实例化bean的逻辑。
FactoryBean接口对于Spring框架来说占有重要的地位,Spring自身就提供了70多个 FactoryBean的实现。它们隐藏了实例化一些复杂bean的细节,给上层应用带来了便利。从Spring 3.0开始,FactoryBean开始支持泛型,即接口声明改为FactoryBean<T>的形式:
public interface FactoryBean<T> { @Nullable T getObject() throws Exception; @Nullable 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。 |
当配置文件中<bean>的class属性配置的实现类是FactoryBean时,通过getBean()方法返回的不是FactoryBean本身,而是FactoryBean#getObject()方法所返回的对象,相当于 FactoiyBean#getObject()代理了 getBean()方法。例如:如果使用传统方式配置下面Car的<bean> 时,Car的每个属性分別对应一个<property>元素标签。
public class Car { private int maxSpeed; private String brand; private double price; // get/set 方法 )
如果用FactoryBean的方式实现就会灵活一些,下例通过逗号分割符的方式一次性地为Car 的所有属性指定配置值:
public class CarFactoryBean implements FactoryBean<Car> { private String carInfo; @Nullable @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; } @Nullable @Override public Class<?> getObjectType() { return Car.class; } @Override public boolean isSingleton() { return false; } // 接受逗号分隔符设置属性信息 public void setCarInfo(String carInfo) { this.carInfo = carInfo; } }
有了这个CarFactoryBean后,就可以在配置文件中使用下面这种自定义的配置方式配置 Car Bean 了:
<bean id="car" class="org.cellphone.uc.CarFactoryBean" carInfo="超级跑车,400,2000000"/>
与调用 getBean("car")时, Spring 通过反射机制发现 CarFactoryBean 实现了 FactoryBean 的接口,这时Spring容器就调用接口方法CarFactoryBean#getObject()方法返回。如果希望获取 CarFactoryBean的实例,则需要在使用getBean(beanName)方法时在beanName前显示的加上 "&"前缀,例如 getBean(”&car")。
以上是关于Spring源码分析FactoryBean的使用的主要内容,如果未能解决你的问题,请参考以下文章
Spring源码分析原型Bean实例化过程byName与byType及FactoryBean获取Bean源码实现
Spring Cloud Feign 源码分析 - FeignClientFactoryBean
Spring源码 BeanFactory和FactoryBean是什么?
Spring - FactoryBean扩展实战_MyBatis-Spring 启动过程源码解读