Spring IOC(四)FactoryBean

Spring 系列目录(https://www.cnblogs.com/binarylei/p/10198698.html)

一般情况下,Spring 通过反射机制利用 bean 的 class 属性指定实现类来实例化 bean。在某些情况下特别是整合第三方包时,实例化 bean 过程比较复杂,如果按照传统的方式,则需要在 XML 中提供大量的配置信息,配置方式的灵活性是受限的,这时采用编码的方式可能会得到一个简单的方案。Spring 为此提供了一个 FactoryBean 的工厂类接口,用户可以通过实现该接口定制实例化 bean 的逻辑。

public interface FactoryBean<T> {
T getObject() throws Exception;
Class<?> getObjectType(); default boolean isSingleton() {
return true;
}
}

在该接口中还定义了以下3个方法:

(1) T getObject():返回由 FactoryBean 创建的 bean 实例,如果 isSingleton() 返回 true,则该实例会放到 Spring 容器中单实例存池中

(2) boolean isSingleton():返回由 FactoryBean 创建的 bean 实例的作用域是 singleton 还是 prototype

(3) Class<?> getObjectType():返回 FactoryBean 创建的 bean 类型。

一、Spring 中使用 FactoryBean

在如下的 Bean 通过 FactoryBean 注入

public class CarFactoryBean implements FactoryBean<Car> {
private String carInfo; @Override
public Car getObject() throws Exception {
String[]infos = carInfo.split(",");
return Car car=new Car(infos[0], Integer.parseInt(infos[1]), Double.parseDouble(infos[2]));
} @Override
public Class<?> getObjectType() {
return null;
}
} public class Car {
private String brand;
private int maxSpeed;
private Double price;
// get/set
}

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

<bean id="car" class="spring.factory_bean.CarFactoryBean">
<property name="carInfo" value="红旗CA72,200,20000.00"/>
</bean>

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

二、FactoryBeanRegistrySupport

FactoryBeanRegistrySupport 提供了对 FactoryBean 的支持,最重要的方法是 getObjectFromFactoryBean(FactoryBean<?> factory, String beanName, boolean shouldPostProcess),这个方法通过 factoryBean 获取 bean 对象。

(1) 属性

// 缓存 beanName -> FactoryBean 的集合
private final Map<String, Object> factoryBeanObjectCache = new ConcurrentHashMap<>(16);

(2) getObjectFromFactoryBean 注册

getObjectFromFactoryBean 负责从 FactoryBean#getObject() 中获取真正想要的 bean 对象,而不是 FactoryBean 本身。AbstractBeanFactory#getObjectForBeanInstance 获取 bean 之前会判断是不是 FactoryBean。

protected Object getObjectFromFactoryBean(FactoryBean<?> factory, String beanName, boolean shouldPostProcess) {
if (factory.isSingleton() && containsSingleton(beanName)) {
synchronized (getSingletonMutex()) {
Object object = this.factoryBeanObjectCache.get(beanName);
if (object == null) {
object = doGetObjectFromFactoryBean(factory, beanName);
// Only post-process and store if not put there already during getObject() call above
// (e.g. because of circular reference processing triggered by custom getBean calls)
// TODO ? 什么意思,循环引用?
Object alreadyThere = this.factoryBeanObjectCache.get(beanName);
if (alreadyThere != null) {
object = alreadyThere;
} else {
if (shouldPostProcess) {
if (isSingletonCurrentlyInCreation(beanName)) {
// Temporarily return non-post-processed object, not storing it yet..
return object;
}
beforeSingletonCreation(beanName);
try {
// 外面 BeanPostProcessor 作用在 factory 上,没有作用在实际想要的实例上,这边补一个
// 也就是说 BeanPostProcessor 的 postProcessBeforeInitialization 不会作用在 FactoryBean 上
object = postProcessObjectFromFactoryBean(object, beanName);
} catch (Throwable ex) {
throw new BeanCreationException(beanName", ex);
} finally {
afterSingletonCreation(beanName);
}
}
if (containsSingleton(beanName)) {
this.factoryBeanObjectCache.put(beanName, object);
}
}
}
return object;
}
} else {
Object object = doGetObjectFromFactoryBean(factory, beanName);
if (shouldPostProcess) {
try {
object = postProcessObjectFromFactoryBean(object, beanName);
} catch (Throwable ex) {
throw new BeanCreationException(beanName, "Post-processing of FactoryBean's object failed", ex);
}
}
return object;
}
} // 调用 FactoryBean#getObject() 创建 bean
private Object doGetObjectFromFactoryBean(final FactoryBean<?> factory, final String beanName)
throws BeanCreationException {
Object object = factory.getObject(); if (object == null) {
if (isSingletonCurrentlyInCreation(beanName)) {
throw new BeanCurrentlyInCreationException(
beanName, "FactoryBean which is currently in creation returned null from getObject");
}
object = new NullBean();
}
return object;
} // 子类重写
protected Object postProcessObjectFromFactoryBean(Object object, String beanName) throws BeansException {
return object;
}

(3) 查找与删除

protected Object getCachedObjectForFactoryBean(String beanName) {
return this.factoryBeanObjectCache.get(beanName);
} @Override
protected void removeSingleton(String beanName) {
synchronized (getSingletonMutex()) {
super.removeSingleton(beanName);
this.factoryBeanObjectCache.remove(beanName);
}
}
@Override
protected void clearSingletonCache() {
synchronized (getSingletonMutex()) {
super.clearSingletonCache();
this.factoryBeanObjectCache.clear();
}
}

(4) 其它方法

protected Class<?> getTypeForFactoryBean(final FactoryBean<?> factoryBean) {
return factoryBean.getObjectType();
} protected FactoryBean<?> getFactoryBean(String beanName, Object beanInstance) throws BeansException {
if (!(beanInstance instanceof FactoryBean)) {
throw new BeanCreationException(beanName,
"Bean instance of type [" + beanInstance.getClass() + "] is not a FactoryBean");
}
return (FactoryBean<?>) beanInstance;
}

每天用心记录一点点。内容也许不重要,但习惯很重要!

最新文章

  1. IIS服务器和xampp中的appche服务器端口冲突解决办法
  2. Linux mount的使用
  3. JNDI解读(转)
  4. Stanford机器学习笔记-5.神经网络Neural Networks (part two)
  5. uva 10755 - Garbage Heap
  6. iOS使用技能 - 短信,语言验证码的获取与验证小结
  7. javascript通过字典思想操作数据
  8. ExecuteNonQuery()返回值
  9. AngularJS: 自定义指令与控制器数据交互
  10. 深入剖析Provider Model
  11. POJ 1185炮兵阵地 (状压DP)
  12. 學習 DT device tree 以 ST 的開發板 STM32F429i-disc1 為例
  13. MySql join on 和 where
  14. 简说chart2.4的应用,以及Uncaught ReferenceError : require is not defined的解决
  15. NYOJ 138 找球号(二) bitset 二进制的妙用
  16. 怎么使用linux命令重启服务器
  17. .Net Core 学习之路-基础
  18. attr跟prop的区别:
  19. python学习日记(数据结构习题)
  20. linux中Java项目占用cpu、内存过高时的排查经历

热门文章

  1. 在Laravel外独立使用laravel-mongodb
  2. 总是Eqw
  3. 大型运输行业实战_day01_1_业务分析
  4. Python 第一个程序_1
  5. @JsonInclude(JsonInclude.Include.NON_NULL) 加在对象上
  6. Aptana在Eclipse的安装
  7. codis
  8. Python+Selenium学习--简单对象定位
  9. 我的图片爬虫demo
  10. glove