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方法,参与到产品初始化的生命周期。

最新文章

  1. JavaScript 命名空间
  2. SQL Pass北京举行2014年第一次线下活动
  3. 网上找到的一个jquery版网页换肤特效
  4. 编译安装php的配置参数详细解析
  5. WindowsCE project missing - 转
  6. 验证码识别--type5
  7. 慕课网-安卓工程师初养成-2-12 如何在Java中使用注释
  8. Delphi 串口使用校验位
  9. leetcode:ZigZag Conversion 曲线转换
  10. webdriver(python)学习笔记七——多层框架定位与智能等待
  11. Read Asia Embedded fell
  12. win32线程池代码(WinApi/C++)
  13. iOS基本内存管理:autorelease和autoreleasepool
  14. SQL Server MySQL 中的 in 与 null
  15. openstack私有云布署实践【4.1 上层代理haproxy配置 (科兴环境)】
  16. windos10安装mongodb并配置
  17. 如何继承Date对象?由一道题彻底弄懂JS继承。
  18. 伪分布式hbase数据迁移汇总
  19. [转]Java事件处理机制- 事件监听器的四种实现方式
  20. hdu-5985 概率DP

热门文章

  1. 20175313 张黎仙《Java程序设计》第十一周学习总结
  2. git常用操作方法
  3. err=&quot;etherbase address must be explicitly specified&quot;
  4. iTerm 2打造ssh完美连接Linux服务器快捷方法
  5. Objective-C如何自己实现一个for-each语法形式
  6. Flex 弹性盒子布局使用教程
  7. 阶段5 3.微服务项目【学成在线】_day02 CMS前端开发_17-CMS前端工程创建-单页面应用介绍
  8. csv解析框架Windmill的一个demo
  9. 二进制安装k8s-单个master节点、两个node--修改版--有个错误:好多地方确少APISERVER
  10. python 时间类型