原文地址:http://www.carlzone.cn/spring...

Spring中有两种类型的Bean,一种是普通Bean,另一种是工厂Bean,即FactoryBean。Spring FactoryBean是创建复杂的bean,一般的bean直接用xml配置即可,如果一个bean的创建过程中涉及到很多其他的bean和复杂的逻辑,用xml配置比较困难,这时可以考虑用FactoryBean.
这两种Bean都被容器管理,但工厂Bean跟普通Bean不同,其返回的对象不是指定类的一个实例,其返回的是该FactoryBean的getObject方法所返回的对象。在Spring框架内部,有很多地方有FactoryBean的实现类,它们在很多应用如(Spring的AOP、ORM、事务管理)及与其它第三框架(ehCache)集成时都有体现,下面简单分析FactoryBean的用法。

1、FactoryBean用法

1)实现FactoryBean接口

/*** Created by Carl on 2016/8/12.*/
public class FactoryBeanTest implements FactoryBean<Object> {private boolean flag;public void setFlag(boolean flag){this.flag = flag;}// 返回这个Bean的实例@Overridepublic Object getObject() throws Exception {return flag ? "carl" : new Date();}// 返回这个类类型@Overridepublic Class<?> getObjectType() {return flag ? String.class : Date.class;}// 是否为单例@Overridepublic boolean isSingleton() {return true;}
}

2)配置XML将Bean纳入Spring管理

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"><bean id="factoryBeanTest1" class="com.weimob.carl.user.dto.FactoryBeanTest"><property name="flag" value="true" /></bean><bean id="factoryBeanTest2" class="com.weimob.carl.user.dto.FactoryBeanTest"><property name="flag" value="false" /></bean></beans>

3)Test

public class Main {public static void main(String[] args) {ApplicationContext context = new ClassPathXmlApplicationContext("application-test.xml");String string = context.getBean("factoryBeanTest1", String.class);Date date = context.getBean("factoryBeanTest2", Date.class);System.out.println(string);System.out.println(date);}}

通过简单的测试可知,该类输出如下:

2、实现原理


大家都知道应该知道BeanFactory在Spring IOC中的作用.它定义了Spring容器的基本方法。其中就包含getBean.由上面的方法调用图我们就可以看到BeanFactory与FactoryBean的关系。下面我们具体看一看代码实现:
1)org.springframework.beans.factory.support.AbstractBeanFactory#getObjectForBeanInstance

protected Object getObjectForBeanInstance(Object beanInstance, String name, String beanName, RootBeanDefinition mbd) {// 如果这里不是对FactoryBean的调用,那么结束处理if (BeanFactoryUtils.isFactoryDereference(name) && !(beanInstance instanceof FactoryBean)) {throw new BeanIsNotAFactoryException(transformedBeanName(name), beanInstance.getClass());}// Now we have the bean instance, which may be a normal bean or a FactoryBean.// If it's a FactoryBean, we use it to create a bean instance, unless the// caller actually wants a reference to the factory.if (!(beanInstance instanceof FactoryBean) || BeanFactoryUtils.isFactoryDereference(name)) {return beanInstance;}Object object = null;if (mbd == null) {object = getCachedObjectForFactoryBean(beanName);}if (object == null) {// Return bean instance from factory.FactoryBean<?> factory = (FactoryBean<?>) beanInstance;// Caches object obtained from FactoryBean if it is a singleton.if (mbd == null && containsBeanDefinition(beanName)) {mbd = getMergedLocalBeanDefinition(beanName);}boolean synthetic = (mbd != null && mbd.isSynthetic());// 这里从FactoryBean中得到Beanobject = getObjectFromFactoryBean(factory, beanName, !synthetic);}return object;
}

2)org.springframework.beans.factory.support.FactoryBeanRegistrySupport#getObjectFromFactoryBean

protected Object getObjectFromFactoryBean(FactoryBean<?> factory, String beanName, boolean shouldPostProcess) {if (factory.isSingleton() && containsSingleton(beanName)) {synchronized (getSingletonMutex()) {// 从cache中获取这个对象Object object = this.factoryBeanObjectCache.get(beanName);if (object == null) {// 从FactoryBean获取这个对象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)Object alreadyThere = this.factoryBeanObjectCache.get(beanName);if (alreadyThere != null) {object = alreadyThere;}else {if (object != null && shouldPostProcess) {try {object = postProcessObjectFromFactoryBean(object, beanName);}catch (Throwable ex) {throw new BeanCreationException(beanName,"Post-processing of FactoryBean's singleton object failed", ex);}}this.factoryBeanObjectCache.put(beanName, (object != null ? object : NULL_OBJECT));}}return (object != NULL_OBJECT ? object : null);}}else {// 从FactoryBean获取这个对象Object object = doGetObjectFromFactoryBean(factory, beanName);if (object != null && shouldPostProcess) {try {object = postProcessObjectFromFactoryBean(object, beanName);}catch (Throwable ex) {throw new BeanCreationException(beanName, "Post-processing of FactoryBean's object failed", ex);}}return object;}
}

3)org.springframework.beans.factory.support.FactoryBeanRegistrySupport#doGetObjectFromFactoryBean

private Object doGetObjectFromFactoryBean(final FactoryBean<?> factory, final String beanName)throws BeanCreationException {Object object;try {if (System.getSecurityManager() != null) {AccessControlContext acc = getAccessControlContext();try {object = AccessController.doPrivileged(new PrivilegedExceptionAction<Object>() {@Overridepublic Object run() throws Exception {// 最终调用FactoryBean.getObject()方法return factory.getObject();}}, acc);}catch (PrivilegedActionException pae) {throw pae.getException();}}else {// 最终调用FactoryBean.getObject()方法object = factory.getObject();}}catch (FactoryBeanNotInitializedException ex) {throw new BeanCurrentlyInCreationException(beanName, ex.toString());}catch (Throwable ex) {throw new BeanCreationException(beanName, "FactoryBean threw exception on object creation", ex);}// Do not accept a null value for a FactoryBean that's not fully// initialized yet: Many FactoryBeans just return null then.if (object == null && isSingletonCurrentlyInCreation(beanName)) {throw new BeanCurrentlyInCreationException(beanName, "FactoryBean which is currently in creation returned null from getObject");}return object;
}

现在大家是不是对FactoryBean与BeanFactory这2个在Spring中非常重要的2个对象理解的很清楚了。

3、FactoryBean的存在价值

上面返回的已经是作为工厂的FactoryBean生产的产品,而不是FactoryBean本身。这种FactoryBean的机制可以为我们提供一个很好的封装机制,比如封装Proxy、RMI/JNDI等。通过对FactoryBean实现过程的原理进行分析,相信大家会对getObject有很深刻的印象。这个方法就是主要的FactoryBean的接口,需要实现特定的工厂的生产过程,至于这个生产过程是怎么和IoC容器整合的,就是在上面的分析的内容。

4、FactoryBean与设计模式

下图是一个典型的工厂模式的UML图。在这里我们可以看看设计模式中的工厂模式,做一个对比,以加深对这些代码的理解。

对比两者的实现,可以看到FactoryBean类似于AbstractFactory抽象工厂,getObjectForBeanInstance()方法类似于createProductA()这样的生产接口,而具体的FactoryBean实现,如TransactionProxyFactoryBean,就是具体的工厂实现,其生成出的TransactionProxy就是"抽象工厂"模式对应的ConcreteProduct.有了抽象工厂设计模式的参考与对比。对FactoryBean的设计和实现就更容易理解一些了。

Spring bean 之 FactoryBean相关推荐

  1. spring学习--bean--普通bean与工厂bean(FactoryBean)区别

    转载:https://blog.csdn.net/weixin_45496190/article/details/107067200 1.Spring 有两种类型 bean,一种普通 bean,另外一 ...

  2. spirng4.0-@Conditional 按条件注册bean、@Import导入组件bean、@FactoryBean spring的bean工厂注册bean

    一.组件说明 @Conditional({xxx.class, xxx.class}),可用在方法和类上面 按照一定的条件进行判断,把满足条件的bean注册到springIOC容器中. @Import ...

  3. Spring Bean四种注入方式(Springboot环境)

    阅读此文建议参考本人写的Spring常用注解:https://blog.csdn.net/21aspnet/article/details/104042826 给容器中注册组件的四种方法:  1.@C ...

  4. 【一步一步学习spring】spring bean管理(上)

    1. spring 工厂类 我们前边的demo中用到的spring 工厂类是ClassPathXmlApplicationContext,从上图可以看到他还有一个兄弟类FileSystemApplic ...

  5. 给容器中注册组件 || @Scope -- @Lazy -- @Conditional({Condition}) -- @Import--使用Spring提供的 FactoryBean

    * @Scope:调整作用域    * prototype:多实例的:ioc容器启动并不会去调用方法创建对象放在容器中.       *              每次获取的时候才会调用方法创建对象: ...

  6. Spring5源码 - 07 Spring Bean 生命周期流程 源码解读02

    文章目录 Pre 通俗流程 finishBeanFactoryInitialization Pre Spring5源码 - 06 Spring Bean 生命周期流程 概述 01 接上文 通俗流程 下 ...

  7. Spring8:一些常用的Spring Bean扩展接口

    前言 Spring是一款非常强大的框架,可以说是几乎所有的企业级Java项目使用了Spring,而Bean又是Spring框架的核心. Spring框架运用了非常多的设计模式,从整体上看,它的设计严格 ...

  8. 实例化Spring Bean:Bean实例化的姿势有多少种?

    <?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.sp ...

  9. Spring bean三种创建方式

    spring共提供了三种实例化bean的方式:构造器实例化(全类名,反射).工厂方法(静态工厂实例化   动态工厂实例化)和FactoryBean ,下面一一详解: 1.构造器实例化 City.jav ...

最新文章

  1. 内核程序中进程的pid,handle,eprocess之间相互转换的方法
  2. CatalanStirling数
  3. R:在Ubuntu14.04 安装R
  4. 【Unity技巧】制作一个简单的NPC
  5. python 多进程 multiprocessing 进程池pool报错 in join assert self._state in (CLOSE, TERMINATE) AssertionError
  6. ITK:将内核与位置上的图像相乘
  7. oracle 10g 关库,Oracle Db10g 启动和关闭数据库
  8. win7下oracle10g安装,专门针对win7下oracle10g安装的详解
  9. 【宝塔】【cloudreve】挂载阿里云OSS到ECS服务器内网上
  10. wps2016热点永久关闭
  11. 浅谈 BOM、EBOM、MBOM
  12. matlab初值随机扰动,GRAPES区域集合预报系统模式不确定性的随机扰动技术研究
  13. ei指什么_什么是EI?
  14. 海上风电消防火灾报警系统中消防主机超远距离联网方案
  15. 2021 CCPC 哈尔滨 E. Power and Modulo (思维题)
  16. Codeforces869B The Eternal Immortality
  17. GEANT4 中的NIST MATERIAL 材料名录
  18. java类的各访问级别,Java构造函数具有比其类更宽的访问级别
  19. 电邮地址_电子邮件如何运作?
  20. object-c的存取权限(public/protected/private)

热门文章

  1. [R语言画图]气泡图symbols
  2. 最新 ECSHOP v2.7.3数据表(88张表)
  3. SQL Server procedure
  4. 联想lenovo Z470笔记本的驱动安装
  5. 如何学习iphone游戏开发
  6. Oracle通用分页包
  7. ASP.NET 应用程序生命周期概述
  8. 毕业设计(3)基于MicroPython的篮球计时计分器模型的设计与实现
  9. Zabbix 中文乱码解决
  10. Docker 17.03系列教程(一)Docker EE/Docker CE简介与版本规划