摘要:本文结合《Spring源码深度解析》来分析Spring 5.0.6版本的源代码。若有描述错误之处,欢迎指正。

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

FactoryBean接口对于Spring框架来说占有重要的地位,Spring自身就提供了70多个 FactoryBean的实现。它们隐藏了实例化一些复杂bean的细节,给上层应用带来了便利。从Spring 3.0开始,FactoryBean开始支持泛型,即接口声明改为FactoryBean<T>的形式:

public interface FactoryBean<T> {

    @Nullable
T getObject() throws Exception; @Nullable
Class<?> getObjectType(); default boolean isSingleton() {
return true;
}
}

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

T getObject() 返回由 FactoryBean 创建的 bean 实例,如果 isSingleton()返回 true,则该实例会放到Spring容器中单实例缓存池中
Class<?> getObjectType() 返回 FactoryBean 创建的 bean 类型
boolean isSingleton() 返回由FactoryBean创建的bean实例的作用域是singleton还是 prototype。

当配置文件中<bean>的class属性配置的实现类是FactoryBean时,通过getBean()方法返回的不是FactoryBean本身,而是FactoryBean#getObject()方法所返回的对象,相当于 FactoiyBean#getObject()代理了 getBean()方法。例如:如果使用传统方式配置下面Car的<bean> 时,Car的每个属性分別对应一个<property>元素标签。

public class Car {
private int maxSpeed;
private String brand;
private double price;
// get/set 方法
)

如果用FactoryBean的方式实现就会灵活一些,下例通过逗号分割符的方式一次性地为Car 的所有属性指定配置值:

public class CarFactoryBean implements FactoryBean<Car> {

    private String carInfo;

    @Nullable
@Override
public Car getObject() throws Exception {
Car car = new Car();
String[] infos = carInfo.split(",");
car.setBrand(infos[0]);
car.setMaxSpeed(Integer.valueOf(infos[1]));
car.setPrice(Double.valueOf(infos[2]));
return car;
} @Nullable
@Override
public Class<?> getObjectType() {
return Car.class;
} @Override
public boolean isSingleton() {
return false;
} // 接受逗号分隔符设置属性信息
public void setCarInfo(String carInfo) {
this.carInfo = carInfo;
}
}

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

<bean id="car" class="org.cellphone.uc.CarFactoryBean" carInfo="超级跑车,400,2000000"/>

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

Spring源码分析(十二)FactoryBean的使用的更多相关文章

  1. spring源码分析系列 (8) FactoryBean工厂类机制

    更多文章点击--spring源码分析系列 1.FactoryBean设计目的以及使用 2.FactoryBean工厂类机制运行机制分析 1.FactoryBean设计目的以及使用 FactoryBea ...

  2. Spring源码分析(二十四)初始化非延迟加载单例

    摘要: 本文结合<Spring源码深度解析>来分析Spring 5.0.6版本的源代码.若有描述错误之处,欢迎指正. 完成BeanFactory的初始化工作,其中包括ConversionS ...

  3. Spring源码分析(二十五)finishRefresh

    摘要: 本文结合<Spring源码深度解析>来分析Spring 5.0.6版本的源代码.若有描述错误之处,欢迎指正. 在 Spring 中还提供了 Lifecycle 接口, Lifecy ...

  4. Spring源码分析(二十二)功能扩展

    摘要: 本文结合<Spring源码深度解析>来分析Spring 5.0.6版本的源代码.若有描述错误之处,欢迎指正. 目录 一.增加SPEL语言的支持 二.增加属性注册编辑器 1. 使用自 ...

  5. Spring源码分析(二十)准备环境

    摘要: 本文结合<Spring源码深度解析>来分析Spring 5.0.6版本的源代码.若有描述错误之处,欢迎指正. prepareRefresh函数主要是做些准备工作,例如对系统属性及环 ...

  6. Spring源码分析(二十三)BeanFactory的后处理

    摘要: 本文结合<Spring源码深度解析>来分析Spring 5.0.6版本的源代码.若有描述错误之处,欢迎指正. 目录 一.激活注册的 BeanFactoryPostProcessor ...

  7. Spring源码分析(二十一)加载BeanFactory

    摘要: 本文结合<Spring源码深度解析>来分析Spring 5.0.6版本的源代码.若有描述错误之处,欢迎指正. 目录 一.定制化BeanFactory 二.加载BeanDefinit ...

  8. Spring源码分析(二)容器基本用法

    摘要:本文结合<Spring源码深度解析>来分析Spring 5.0.6版本的源代码.若有描述错误之处,欢迎指正. 在正式分析Spring源码之前,我们有必要先来回顾一下Spring中最简 ...

  9. ABP源码分析十二:本地化

    本文逐个分析ABP中涉及到locaization的接口和类,以及相互之间的关系.本地化主要涉及两个方面:一个是语言(Language)的管理,这部分相对简单.另一个是语言对应得本地化资源(Locali ...

  10. [Abp 源码分析]十二、多租户体系与权限验证

    0.简介 承接上篇文章我们会在这篇文章详细解说一下 Abp 是如何结合 IPermissionChecker 与 IFeatureChecker 来实现一个完整的多租户系统的权限校验的. 1.多租户的 ...

随机推荐

  1. Code Signal_练习题_shapeArea

    A 1-interesting polygon is just a square with a side of length 1. An n-interesting polygon is obtain ...

  2. LOJ#6463 AK YOI 树分治+线段树合并

    传送门 既然是树上路径统计问题,不难想到要使用树分治,这里以点分治为例 由点分治的性质,每层只需要考虑经过重心的路径 因为需要维护路径长度在一定范围内的最大权值和,所以要用一个数据结构维护一下到根节点 ...

  3. BZOJ4144: [AMPPZ2014]Petrol(最短路 最小生成树)

    题意 题目链接 Sol 做的时候忘记写题解了 可以参考这位大爷 #include<bits/stdc++.h> #define Pair pair<int, int> #def ...

  4. centos文件基本操作

    centos彻底删除文件夹.文件命令(centos 新建.删除.移动.复制等命令: 1.新建文件夹 mkdir 文件名 新建一个名为test的文件夹在home下 view source1 mkdir ...

  5. 那些年我们对npm 和 cnpm 的误区

    1. npm 和 cnpm 的区别 相信很多人都不太明白 npm 和 cnpm 到底是什么东东, 为啥在国内要用 淘宝镜像使用 cnpm, (1) 两者之间只是 node 中包管理器的不同哟, (2) ...

  6. CentOS7.4 + Hadoop2.7.5安装配置管理(伪分布式)

    1.  规划 1.1.  机器列表 NameNode SecondaryNameNode DataNodes 192.168.1.80 192.168.1.80 192.168.1.80 1.2.  ...

  7. 网络I/O模型--04非阻塞模式(解除accept()、 read()方法阻塞)的基础上加入多线程技术

    由于应用程序级别并没有使用多线程技术,这就导致了应用程序只能一个一个地对Socket 套接字进行处理.这个 Socket 套接宇没有处理完,就没法处理下一个 Socket 套接字 .针对这个 问题还是 ...

  8. linux rabbitmq 安装

    下载 在安装 erlang 时使用的是源码包21.0版本:接着下载 rabbitmq-server/3.7.7 的源码包,编译时报错,说 erlang 版本号不满足条件,erlang版本>=19 ...

  9. Android UI组件----用相对布局RelativeLayout做一个登陆界面

    [声明] 欢迎转载,但请保留文章原始出处→_→ 生命壹号:http://www.cnblogs.com/smyhvae/ 文章来源:http://www.cnblogs.com/smyhvae/p/3 ...

  10. sql server单个字段列转行由,隔开

    SELECT STUFF((SELECT ','+字段名 FROM 表名 for xml path('')),1,1,'')