简单分析FactoryBean
1. 什么是FactoryBean
FactoryBean本质上是一种Bean,只是它可以产生其他的Bean,比较特殊。在上下文getBean的时候,如果传入FactoryBean的名称,得到的是FactoryBean生产的产品,而不是FactoryBean。如果要获得FactoryBean自身,那么传入的FactoryBean名称前面要加上&字符。
2. 一个小例子
package com.khlin.my.test; import org.springframework.beans.factory.FactoryBean;
import java.util.Date; public class DefaultFactoryBean implements FactoryBean<Date> {
public Date getObject() throws Exception {
return new Date();
} public Class<?> getObjectType() {
return Date.class;
} public boolean isSingleton() {
return true;
}
}
<bean id="defaultFactoryBean" class="com.khlin.my.test.DefaultFactoryBean"/>
再来个启动类
package com.khlin.my.test; import org.springframework.beans.factory.FactoryBean;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext; import java.util.Date; public class FactoryBeanTest { public static void main(String[] args) {
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("classpath:applicationContext.xml");
Date date = (Date) applicationContext.getBean("defaultFactoryBean");
System.out.println(date);
DefaultFactoryBean factoryBean = (DefaultFactoryBean) applicationContext.getBean("&defaultFactoryBean");
}
}
可以看到,如果要获得产品,直接使用FactoryBean的名称。如果要获得工厂,则要在前面加上&
3. 原理分析
在getBean方法里,层层调用,到了AbstractBeanFactory的getObjectForBeanInstance方法,无论是获取产品还是工厂,都是先取出工厂类的Bean。

然后对其进行类型判断。
3.1 如果是FactoryBean并且名称不是以&开头,说明要取出产品。先是从缓存里取出产品,如果产品不存在,从工厂类中取出。

对于单例的产品,会存储在FactoryBeanRegistrySupport的factoryBeanObjectCache里。这是一个Map,由工厂名映射到产品。
第一次获取,肯定是为空。那么就会调用getObjectFromFactoryBean方法。在这个方法里,会先调用工厂的getObject()方法,最后放入缓存中。这样后面取产品,就可以从缓存中取出,实现了单例的语义。
要注意的是,虽然产品是通过getObject()直接得到的,不是Spring Bean,但中间还是用BeanPostProcessor参与了其生命周期。

最终会进入到AbstractAutowireCapableBeanFactory类。这里只调用了After的方法,没有调用Before.

对于多例,getObjectForBeanInstance方法里,从缓存里取不出产品,同样调用getObjectFromFactoryBean。
不同的是这次走入另一条分支。仍是调用getObject生产产品,再用BeanPostProcessors后处理,不过这次没有将其放入缓存。这也符合多例的语义,每次获得的都是新的对象。

3.2 如果是FactoryBean但不是以&开头,只能走到最后一个分支,直接取出FactoryBean对象。
重温上面的代码图,即走入最后一个分支,return beanInstance.

4. 总结
单例的产品会放在缓存里,键为工厂名,值为产品。
多例的产品不会放在缓存。
创建产品是直接调用工厂的getObject方法,因此产品没有Spring Bean的生命周期。
每次创建完一个产品,会调用所有注册的BeanPostProcessors的postProcessAfterInitialization方法,参与到产品初始化的生命周期。
简单分析FactoryBean的更多相关文章
- 简单分析JavaScript中的面向对象
初学JavaScript的时候有人会认为JavaScript不是一门面向对象的语言,因为JS是没有类的概念的,但是这并不代表JavaScript没有对象的存在,而且JavaScript也提供了其它的方 ...
- CSipSimple 简单分析
简介 CSipSimple是一款可以在android手机上使用的支持sip的网络电话软件,可以在上面设置使用callda网络电话.连接使用方式最好是使用wifi,或者3g这样上网速度快,打起电话来效果 ...
- C#中异常:“The type initializer to throw an exception(类型初始值设定项引发异常)”的简单分析与解决方法
对于C#中异常:“The type initializer to throw an exception(类型初始值设定项引发异常)”的简单分析,目前本人分析两种情况,如下: 情况一: 借鉴麒麟.NET ...
- 透过byte数组简单分析Java序列化、Kryo、ProtoBuf序列化
序列化在高性能网络编程.分布式系统开发中是举足轻重的之前有用过Java序列化.ProtocolBuffer等,在这篇文章这里中简单分析序列化后的byte数组观察各种序列化的差异与性能,这里主要分析Ja ...
- 简单分析Java的HashMap.entrySet()的实现
关于Java的HashMap.entrySet(),文档是这样描述的:这个方法返回一个Set,这个Set是HashMap的视图,对Map的操作会在Set上反映出来,反过来也是.原文是 Returns ...
- Ffmpeg解析media容器过程/ ffmpeg 源代码简单分析 : av_read_frame()
ffmpeg 源代码简单分析 : av_read_frame() http://blog.csdn.net/leixiaohua1020/article/details/12678577 ffmpeg ...
- FFmpeg的HEVC解码器源码简单分析:解析器(Parser)部分
===================================================== HEVC源码分析文章列表: [解码 -libavcodec HEVC 解码器] FFmpeg ...
- FFmpeg资料来源简单分析:libswscale的sws_getContext()
===================================================== FFmpeg库函数的源代码的分析文章: [骨架] FFmpeg源码结构图 - 解码 FFmp ...
- wp7之换肤原理简单分析
wp7之换肤原理简单分析 纠结很久...感觉勉强过得去啦.还望各位大牛指点江山 百度找到这篇参考文章http://www.cnblogs.com/sonyye/archive/2012/03/12/2 ...
随机推荐
- 关系型数据库的树形结构查询(Oracle、Postgres)
Oracle : start with… connect by 的用法.语法:select * from table [where 条件1] connect by[条件2] start with[条件 ...
- Linux之破解root密码
破解CentOs6的root口令 进入单用户模式 重启后在下面界面按任意键 进入此界面后“ a ”在下面界面 输入1 进入单用户模式1之前有空格 按回车键进入命令行执行passwd命令直接修 ...
- CentOS7 docker开启tcp端口并进行客户端远程连接
#docker版本:18.09.0,最好保证客户端端口和服务端端口相同 [root@Centos7 ~]# dockerd-ce -v Docker version , build 4d60db4 网 ...
- ccf 201803-2 碰撞的小球(Python)
问题描述 数轴上有一条长度为L(L为偶数)的线段,左端点在原点,右端点在坐标L处.有n个不计体积的小球在线段上,开始时所有的小球都处在偶数坐标上,速度方向向右,速度大小为1单位长度每秒. 当小球到达线 ...
- Activiti核心API
ProcessEngine 说明: 1) 在Activiti中最核心的类,其他的类都是由他而来. 2) 产生方式: 在前面看到了两种创建ProcessEngine(流程引擎)的方式 ...
- C之枚举
#include<stdio.h>#include<stdlib.h>enum WeekDay{ Monday,Tuesday,Wednesday,Thursday,Frida ...
- idea调试jdk1.8源码(最新)
我们发现如果,直接用idea点项目jdk源码进去后发现自己不能注释说明,非常麻烦,不便阅读记录 于是: 1.在安装的jdk1.8路径下,找到src.zip和javafx-src.zip压缩文件 ,解压 ...
- 如何解决docker 官方镜像拉取慢的问题
转自: http://skycity.today/?thread-307.htm 国内从 docker 官方 Registry 拉取 image 慢的解决,步骤如下: 1.注册一个阿里云账号. 2.阿 ...
- 当微信小程序遇到AR(二)
当微信小程序遇到AR,会擦出怎么样的火花?期待与激动...... 通过该教程,可以从基础开始打造一个微信小程序的AR框架,所有代码开源,提供大家学习. 本课程需要一定的基础:微信开发者工具,JavaS ...
- Tomcat 部署web 项目
转载,原文链接: https://www.cnblogs.com/ysocean/p/6893446.html 侵删 回到顶部 3.Tomcat 的目录结构 回到顶部 4.部署项目的第一种方法(项目直 ...