Spring IOC(四)FactoryBean
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;
}
每天用心记录一点点。内容也许不重要,但习惯很重要!
Spring IOC(四)FactoryBean的更多相关文章
- Spring IOC容器启动流程源码解析(四)——初始化单实例bean阶段
目录 1. 引言 2. 初始化bean的入口 3 尝试从当前容器及其父容器的缓存中获取bean 3.1 获取真正的beanName 3.2 尝试从当前容器的缓存中获取bean 3.3 从父容器中查找b ...
- 【Spring IoC】依赖注入DI(四)
平常的Java开发中,程序员在某个类中需要依赖其它类的方法.通常是new一个依赖类再调用类实例的方法,这种开发存在的问题是new的类实例不好统一管理. Spring提出了依赖注入的思想,即依赖类不由程 ...
- Spring Ioc源码分析系列--容器实例化Bean的四种方法
Spring Ioc源码分析系列--实例化Bean的几种方法 前言 前面的文章Spring Ioc源码分析系列--Bean实例化过程(二)在讲解到bean真正通过那些方式实例化出来的时候,并没有继续分 ...
- J2EE进阶(十四)超详细的Java后台开发面试题之Spring IOC与AOP
J2EE进阶(十四)超详细的Java后台开发面试题之Spring IOC与AOP 前言 搜狐畅游笔试题中有一道问答题涉及到回答谈谈对Spring IOC与AOP的理解.特将相关内容进行整理. ...
- Spring IOC(四)总结升华篇
本系列目录 Spring IOC(一)概览 Spring IOC(二)容器初始化 Spring IOC(三)依赖注入 Spring IOC(四)总结升华 =============正文分割线===== ...
- spring IOC中四种依赖注入方式
在spring ioc中有三种依赖注入,分别是:https://blog.csdn.net/u010800201/article/details/72674420 a.接口注入:b.setter方法注 ...
- 转:深入浅出spring IOC中四种依赖注入方式
转:https://blog.csdn.net/u010800201/article/details/72674420 深入浅出spring IOC中四种依赖注入方式 PS:前三种是我转载的,第四种是 ...
- 六、spring之通过FactoryBean为ioc容器中添加组件
前面我们已经介绍了几种为容器中添加组件的方法,今天一起学习通过FactoryBean添加组件的方法. 首先我们准备一个类,也就是我们需要注册进spring的ioc容器中的类 类Color: // 不必 ...
- spring(四):IoC
IoC-Inversion of Control,即控制反转 IoC意味着将你设计好的对象交给容器控制,而不是传统的在你的对象内部直接控制. 理解IoC的关键:"谁控制谁,控制什么,为何是反 ...
随机推荐
- KMP与AC自动机模板
HDU 1711 Number Sequence(KMP模板题) http://acm.hdu.edu.cn/showproblem.php?pid=1711 #include<bits/std ...
- zxing解析带logo二维码会报com.google.zxing.NotFoundException
参考原文:https://blog.csdn.net/cyl1226541/article/details/70557232 //复杂模式,开启PURE_BARCODE模式(☆☆☆) HINTS.pu ...
- pring Boot 与Spring Cloud版本对应
Spring Boot Spring Cloud 1.2.x Angel版本 1.3.x Brixton版本 1.4.x Camden版本 1.5.x Dalston版本.Edgware版本 2.0. ...
- 设计table表格,用js设计偶数行和奇数行显示不同的颜色
第一种:鼠标经过时table表格中的颜色根据奇偶行改变不同的颜色 <!DOCTYPE html> <html> <head> <meta charset=&q ...
- Log4j2配置及使用
Log4j2:一个日志管理工具.Log4j的升级版,需要Java6以上 一.安装log4j2依赖包 1.通过maven的pom.xml直接引入jar: log4j-api和log4j-core & ...
- 1、__del__ 2、item系列 3、__hash__ 4、__eq__
1.__del__ 析构方法 释放一个空间之前之前 垃圾回收机制 2.item系列 和对象使用[ ]访问值有联系 __getitem__ __setitem__ __delit ...
- python读写文件中read()、readline()和readlines()的用法
python中有三种读取文件的函数: read() readline() readlines() 然而它们的区别是什么呢,在平时用到时总会遇到,今天总结一下. 0. 前期工作 首先新建一个文件read ...
- POJ-1321.棋盘问题.(回溯)
做完题之后看了网上的一些题解但是发现他们的解释大部分都是错误的,所以就自己写了一下,笔者能力也有限,有错误之处大家多多指正. 第一次看题的时候以为就是简单的八皇后,但是写了之后发现存在很多问题,比如需 ...
- Mobile Game Development with Unity Build Once, Deploy Anywhere
本书从自上而下的角度介绍了Unity游戏引擎的功能,并提供了具体的.面向项目的指导,说明了如何在真实的游戏场景中使用这些功能,以及如何从头开始构建让玩家爱不释手的2D和3D游戏.主要内容有:探索Uni ...
- TZOJ 1937 Hie with the Pie(floyd+状压dp)
描述 The Pizazz Pizzeria prides itself in delivering pizzas to its customers as fast as possible. Unfo ...