Spring 源码学习(2) —— FactoryBean 的使用
一般情况下, Spring是通过反射机制利用bean的class属性指定实现类来完成实例化bean的。在某些特定的情况下, 想做一些定制,Spring为此提供了一个org.springframework.beans.factory.FactoryBean的工厂类接口, 用户可以通过实现该接口定制实例化bean的逻辑。
Spring从3.0开始, FactoryBean开始支持泛型, 即接口声明改为: FactoryBean<T> 的形式。
package org.springframework.beans.factory;
public interface FactoryBean<T> {
/**
*
* @return 返回由FactoryBean创建的bean实例, 如果isSingleton()返回true, 则该实例则会放到Spring容器单实例缓存池中
* @throws Exception
*/
T getObject() throws Exception;
/**
*
* @return 返回FactoryBean创建Bean的类型
*/
Class<?> getObjectType();
/**
*
* @return 返回有FactoryBean创建的bean实例的作用域是singleten还是prototype
*/
boolean isSingleton();
}
Action
创建一个pojo类<Car>。
/**
* @filename: Car.java
* @author: Wang Chinda
* @date: 2018-05-22
* @version: v1.0
* @modify_history: -
* 20180522 Wang Chinda create
* 20180522 Wang Chinda modify method()
*/
package com.itdoc.learn.source.factory; /**
* @desc FactoryBean 的使用
* @author Wang Chinda
* @create 2018-05-22 16:07
*/
public class Car {
/** 最大速度 */
private int maxSpeed;
/** 品牌 */
private String brand;
/** 价钱 */
private double price; public int getMaxSpeed() {
return maxSpeed;
} public void setMaxSpeed(int maxSpeed) {
this.maxSpeed = maxSpeed;
} public String getBrand() {
return brand;
} public void setBrand(String brand) {
this.brand = brand;
} public double getPrice() {
return price;
} public void setPrice(double price) {
this.price = price;
} @Override
public String toString() {
return "Car{" +
"maxSpeed=" + maxSpeed +
", brand='" + brand + '\'' +
", price=" + price +
'}';
}
}
创建一个定制实例化bean逻辑的类<CarFactoryBean>:
/**
* @filename: CarFactoryBean.java
* @author: Wang Chinda
* @date: 2018-05-22
* @version: v1.0
* @modify_history: -
* 20180522 Wang Chinda create
* 20180522 Wang Chinda modify method()
*/
package com.itdoc.learn.source.factory; import org.springframework.beans.factory.FactoryBean; /**
* @desc FactoryBean测试的工厂类
* @author Wang Chinda
* @create 2018-05-22 16:17
*/
public class CarFactoryBean implements FactoryBean<Car> { /** 车的详细信息 */
private String carInfo; @Override
public Car getObject() throws Exception {
Car car = new Car();
String[] infos = carInfo.split(",");
car.setBrand(infos[0].trim());
car.setMaxSpeed(Integer.valueOf(infos[1].trim()));
car.setPrice(Double.valueOf(infos[2].trim()));
return car;
} @Override
public Class<Car> getObjectType() {
return Car.class;
} @Override
public boolean isSingleton() {
return false;
} public String getCarInfo() {
return carInfo;
} public void setCarInfo(String carInfo) {
this.carInfo = carInfo;
}
}
配置xml<car-factory-bean.xml>:
<?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="car" class="com.itdoc.learn.source.factory.CarFactoryBean">
<property name="carInfo" value="超级跑车, 400, 300000000"></property>
</bean> </beans>
测试<Car>:
/**
* @filename: CarClient.java
* @author: Wang Chinda
* @date: 2018-05-22
* @version: v1.0
* @modify_history: -
* 20180522 Wang Chinda create
* 20180522 Wang Chinda modify method()
*/
package com.itdoc.learn.source.factory; import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext; /**
* @desc FactoryBean使用测试客户端入口
* @author Wang Chinda
* @create 2018-05-22 16:27
*/
public class CarClient {
public static void main(String[] args) {
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("test/car-factory-bean.xml");
Car car = (Car) applicationContext.getBean("car");
System.out.println(car);
}
}
控制台打印:

流程分析:
当配置文件中<bean>的class属性配置类的实现类是FactoryBean时, 通过getBean返回的不是FactoryBean本身, 而是FactoryBean#getObject()方法返回的对象, 相当于FactoryBean#getObject()代理了getBean()方法。
从缓存中或者singletonFactories中的ObjectFactory中获取共享实例。
Object sharedInstance = getSingleton(beanName);

bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd); 获取对应实例。
强制将共享实例转化成FactoryBean。FactoryBean<?> factory = (FactoryBean<?>) beanInstance;
object = getObjectFromFactoryBean(factory, beanName, !synthetic); 在FactoryBean中获取bean实例。

doGetObjectFromFactoryBean(factory, beanName, shouldPostProcess);
调用getObject()方法,object = factory.getObject();


返回实例bean。
GitHub源码: https://github.com/wcd19901010/spring-01
Spring 源码学习(2) —— FactoryBean 的使用的更多相关文章
- spring源码学习之路---深入AOP(终)
作者:zuoxiaolong8810(左潇龙),转载请注明出处,特别说明:本博文来自博主原博客,为保证新博客中博文的完整性,特复制到此留存,如需转载请注明新博客地址即可. 上一章和各位一起看了一下sp ...
- Spring源码学习
Spring源码学习--ClassPathXmlApplicationContext(一) spring源码学习--FileSystemXmlApplicationContext(二) spring源 ...
- Spring源码学习-容器BeanFactory(三) BeanDefinition的创建-解析Spring的默认标签
写在前面 上文Spring源码学习-容器BeanFactory(二) BeanDefinition的创建-解析前BeanDefinition的前置操作中Spring对XML解析后创建了对应的Docum ...
- Spring 源码学习笔记10——Spring AOP
Spring 源码学习笔记10--Spring AOP 参考书籍<Spring技术内幕>Spring AOP的实现章节 书有点老,但是里面一些概念还是总结比较到位 源码基于Spring-a ...
- Spring源码学习笔记12——总结篇,IOC,Bean的生命周期,三大扩展点
Spring源码学习笔记12--总结篇,IOC,Bean的生命周期,三大扩展点 参考了Spring 官网文档 https://docs.spring.io/spring-framework/docs/ ...
- spring源码学习之路---IOC初探(二)
作者:zuoxiaolong8810(左潇龙),转载请注明出处,特别说明:本博文来自博主原博客,为保证新博客中博文的完整性,特复制到此留存,如需转载请注明新博客地址即可. 上一章当中我没有提及具体的搭 ...
- Spring源码学习-容器BeanFactory(四) BeanDefinition的创建-自定义标签的解析.md
写在前面 上文Spring源码学习-容器BeanFactory(三) BeanDefinition的创建-解析Spring的默认标签对Spring默认标签的解析做了详解,在xml元素的解析中,Spri ...
- Spring源码学习-容器BeanFactory(二) BeanDefinition的创建-解析前BeanDefinition的前置操作
写在前面 上文 Spring源码学习-容器BeanFactory(一) BeanDefinition的创建-解析资源文件主要讲Spring容器创建时通过XmlBeanDefinitionReader读 ...
- Spring源码学习-容器BeanFactory(一) BeanDefinition的创建-解析资源文件
写在前面 从大四实习至今已一年有余,作为一个程序员,一直没有用心去记录自己工作中遇到的问题,甚是惭愧,打算从今日起开始养成写博客的习惯.作为一名java开发人员,Spring是永远绕不过的话题,它的设 ...
随机推荐
- 7. B+树
一.B+树是应文件系统所需而产生的一种B树的变形树 1. 定义(使用阶数m来定义) 除了根结点外,其他非终端结点最多有m个关键字,最少有⌈m/2⌉个关键字 结点中的每个关键字对应一个子树 所有的非终端 ...
- C++:默认初始化
一.什么是默认初始化 默认初始化,顾名思义,即为在定义变量时如果没有为其指定初始化值,则该变量会被C++编译器赋予默认的值.而变量被赋予的默认值到底是什么,则取决于变量的数据类型和变量的定义位置. 二 ...
- Android开发第二阶段(1)
今天:总结第一阶段的冲刺成果,第一阶段就是主要是学习andriod开发,参考文件有<黑马教学视频><Mars教学视频>...结果在看的过程遇到很多问题特别是对java的一些理解 ...
- ImportError: No module named examples.tutorials.mnist
Traceback (most recent call last): File "nearest_neighbor.py", line 14, in <module> ...
- VSVC2010中常用的C++11特性
static_assert 声明 static_assert 声明在编译时测试软件断言,这与在运行时进行测试的其他断言机制不同. 如果断言失败,则编译也将失败,且系统将发出指定的错误消息. const ...
- MySQL---索引算法B+/B-树原理(二)
B+/-Tree原理 B-Tree介绍 B-Tree是一种多路搜索树(并不是二叉的): 1.定义任意非叶子结点最多只有M个儿子:且M>2: 2.根结点的儿子数为[2, ...
- 【Python】python操作mysql
pymysql模块对mysql进行 import pymysql # 创建连接 conn = pymysql.connect(host=, user='root', passwd='root', db ...
- struts 普通的action
1.使用普通方式javaBean作为Action动作类,不需要继承任何父类,也不需要实现接口. l 方法一定是public公用的, l 返回值是字符串用来决定跳转到哪个视图 l 不需要参数 l 方法名 ...
- BZOJ 2006 超级钢琴(堆+主席树)
很好的一道题. 题意:给出长度为n的数列,选择k个互不相同的区间,满足每个区间长度在[L,R]内,求所有选择的区间和的总和最大是多少.(n,k<=5e5). 首先将区间和转化为前缀和之差,那么我 ...
- 洛谷P2894[USACO08FEB]酒店Hotel(线段树)
问题描述 奶牛们最近的旅游计划,是到苏必利尔湖畔,享受那里的湖光山色,以及明媚的阳光.作为整个旅游的策划者和负责人,贝茜选择在湖边的一家著名的旅馆住宿.这个巨大的旅馆一共有N (1 <= N & ...