一、FactoryBean的作用
Spring 中有两种 bean ,一种是普通 bean ,另外一种则是 FactoryBean. 普通 bean 返回的是指定类的一个实例对象,而 FactoryBean 则不同,它返回的对象不是某一个指定类的实例对象,而是该 FactoryBean 的 getObject() 方法所返回的对象,创建出来的对象是单例还是多例,由 FactoryBean 的 isSingleton() 方法来控制.
一般情况下, Spring 通过获取 bean 标签中配置的 class 属性的全类名,通过反射(Class.forName(String className)来创建 bean 对象,但是在某些情况下,有一些 bean 的实例化过程比较复杂,如果按照传统的方式,则需要在 <bean...> 标签中配置大量的信息,配置方式的灵活性是受限制的,这个时候通过获取配置然后编码的方式来实例化 bean,可能只会得到一个简单的方案,不能满足我们实际的需求,为了解决这个问题, Spring 为此提供了一个 org.springframework.bean.factory.FactoryBean 的工厂类接口,用户可以通过实现该接口,通过该接口实现类中的 getObject() 方法私人订制 bean 的实现逻辑,这样就大大的增加了灵活性.同时这样也可以隐藏实例化 bean 的一些复杂的细节,给上层的调用带来了便利.
二、FactoryBean的使用特点
实现了 FactoryBean 接口的 bean 如果通过配置的 id 去获取,获取到的是 FactoryBean 调用 getObject()方法返回的对象,而不是FactoryBean 本身,如果想要获取到 FactoryBean 本身,需要在 id前面加上一个 & 符号,例如:
applicationContext.getBean("&id")
三、FactoryBean 案例演示
1、FactoryBean 接口的实现类
// 自定义类 Person 实现 FactoryBean 接口
public class Person implements FactoryBean<Mango> {
@Override
public Mango getObject() throws Exception {
Mango mango = new Mango();
mango.setName("mango");
mango.setColor("yellow");
mango.setColor("10.0");
return mango;
}
@Override
public Class<?> getObjectType() {
return null;
}
@Override
public boolean isSingleton() {
// 返回值是 true,代表创建的 Mango 对象是单例的,反之为多例
return true;
}
}
2、spring 配置文件(classpath:spring-config/spring-ioc.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="person" class="com.xiaomaomao.entity.Person"></bean>
</beans>
3、测试类
public class SpringTest {
public static void main(String[] args) {
ApplicationContext ioc = new ClassPathXmlApplicationContext("classpath:spring-config/spring-ioc.xml");
// 获取到的是 FactoryBean 本身实例对象
Object person01 =ioc.getBean("&person");
// 获取到的是 FactoryBean 调用 getObject() 方法返回的对象
Object person02 = ioc.getBean("person");
Object person03 = ioc.getBean("person");
// 输出 FactoryBean 本身实例对象
System.out.println(person01);
// 输出 FactoryBean 调用 getObject() 方法返回的对象
System.out.println(person02);
// 判断 FactoryBean 调用 getObject() 方法返回的对象是不是单例
System.out.println(person02 == person03);
}
}
4、测试结果
通过测试结果,我们可以得出以下结论:
(1)、getBean("&id") 获取到的是 FactoryBean 本身对象
(2)、getBean("id") 获取到的是 FactoryBean 调用 getObject() 方法返回的对象
(3)、isSingleton() 方法可以控制 FactoryBean 调用 getObject() 方法返回的对象是单例还是多例
四、FactoryBean 的实际应用
就拿 Mybatis 来说吧,我们也是通过注入一个 SqlSessionFactoryBean ,实际上使用的却是 SqlSessionFactoryBean 对象通过调用 getObject() 方法返回的 SqlSessionFactory 对象.
<!-- spring 和 MyBatis 整合,不需要 mybatis 的配置映射文件 -->
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="dataSource"/>
<!-- 自动扫描 mapping.xml 文件 -->
<property name="mapperLocations" value="classpath:mapper/*.xml"></property>
</bean>
五、FactoryBean 源码解析
说到这里就简单说一下 FactoryBean 的初始化和获取 IOC 中的 bean 的过程吧
// DefaultListableBeanFactory 类中的方法,代码行号: 728
public void preInstantiateSingletons() throws BeansException {
if (this.logger.isDebugEnabled()) {
this.logger.debug("Pre-instantiating singletons in " + this);
}
// 这里的 this 代表的是 DefaultListableBeanFactory
// 这个类里面封装了 spring 配置文件中所有,bean 标签的配置信息
List<String> beanNames = new ArrayList<String>(this.beanDefinitionNames);
// 触发所有非懒加载的单例 bean 的初始化动作
for (String beanName : beanNames) {
// 合并父 bean 的配置
RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName);
// 非懒加载、非抽象的单例 bean
if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) {
// 判断当前 bean 是否是 FactoryBean (我们配置的 person 这个 bean 由于实现了 FactoryBean 这个接口
// 所以它属于 FactoryBean
if (isFactoryBean(beanName)) {
// FactoryBean 的初始化动作,这里的 FACTORY_BEAN_PREFIX 是一个前缀 &
final FactoryBean<?> factory = (FactoryBean<?>) getBean(FACTORY_BEAN_PREFIX + beanName);
boolean isEagerInit;
if (System.getSecurityManager() != null && factory instanceof SmartFactoryBean) {
isEagerInit = AccessController.doPrivileged(new PrivilegedAction<Boolean>() {
@Override
public Boolean run() {
return ((SmartFactoryBean<?>) factory).isEagerInit();
}
}, getAccessControlContext());
}
else {
isEagerInit = (factory instanceof SmartFactoryBean &&
((SmartFactoryBean<?>) factory).isEagerInit());
}
if (isEagerInit) {
getBean(beanName);
}
}
else {
// 普通 bean 的初始化
getBean(beanName);
}
}
}
// 到这里为止,我们所说的非懒加载非抽象的所有 singleton bean 已经初始化完毕
// 如果我们定义的 bean 实现了 SmartInitializingSingleton 这个接口,那么会在这里回调
for (String beanName : beanNames) {
Object singletonInstance = getSingleton(beanName);
if (singletonInstance instanceof SmartInitializingSingleton) {
final SmartInitializingSingleton smartSingleton = (SmartInitializingSingleton) singletonInstance;
if (System.getSecurityManager() != null) {
AccessController.doPrivileged(new PrivilegedAction<Object>() {
@Override
public Object run() {
smartSingleton.afterSingletonsInstantiated();
return null;
}
}, getAccessControlContext());
}
else {
smartSingleton.afterSingletonsInstantiated();
}
}
}
}
由于我们在 Spring 的配置文件中配置的 bean 是一个 FactoryBean ,所以我们点进去 (FactoryBean<?>) getBean(FACTORY_BEAN_PREFIX + beanName) 这个方法看一下,这个方法的参数是 &person (person 这个是 id ,我们在配置文件中配置的,解析 XML 的时候,这个 id 就赋值给了我们这里的 beanName)
// AbstractBeanFactory 类中的方法,代码行号: 196
public Object getBean(String name) throws BeansException {
return doGetBean(name, null, null, false);
}
同时可以看一下下面几个重载的方法,这个几个方法是我们获取 IOC 容器中 bean 的一些方法,当然上面那个方法既可以初始化 bean,也可以获取 IOC 容器中的 bean 对象
// 获取 bean 的时候 ioc.getBean("person",Person.class)
public <T> T getBean(String name, Class<T> requiredType) throws BeansException {
return doGetBean(name, requiredType, null, false);
}
// 获取 bean 的时候 ioc.getBean("person","xiaomao")
public Object getBean(String name, Object... args) throws BeansException {
return doGetBean(name, null, args, false);
}
// 获取 bean 的时候 ioc.getBean("person", Person.class,"xiaomao","xiaomaomao")
public <T> T getBean(String name, Class<T> requiredType, Object... args) throws BeansException {
return doGetBean(name, requiredType, args, false);
}
不管是初始化 bean 还是获取 IOC 容器中的 bean ,我们都最终会调用 doGetBean(....) 这个方法,只是不同的需求下传入的参数值不同而已.点进去这个方法,看看里面到底有什么
// AbstractBeanFactory 类中的方法,代码行号: 235
protected <T> T doGetBean(
final String name, final Class<T> requiredType, final Object[] args, boolean typeCheckOnly)
throws BeansException {
// 对于普通的 bean,不管是初始化 bean 还是获取 bean, beanName 的值是不会有变化的,自始至终都是一样
// 而对于 FactoryBean 来说,初始化 bean 的时候,由于传进来的参数 name 是带有 & 符号的,例如 &person
// 这里是想真正的获取到 FactoryBean 的 beanName ,所以会去掉 & 符号
final String beanName = transformedBeanName(name);
// 这个要关注一下,创建 bean 、获取 bean 的返回值
Object bean;
// 判断父容器中是否已经创建过了该单例 bean
// 第一次初始化的时候,这里是没有创建过该单例 bean 的,所以值为 null
// 如果是后面通过 getBean(...) 来获取的 bean 实例的时候,因为初始化已经创建了 bean ,所以这里就不会为 null
Object sharedInstance = getSingleton(beanName);
// 如果没有创建该 singleton bean ,并且传入的参数为 null ,那么执行获取 bean 的操作
// 如果获取 bean 实例的时候,传入了 args 参数,因为已经创建过了该 bean 实例,所以 sharedInstance 不为 null
// 这个时候如果传入的 args 参数不为 null ,那么就不满足该条件,这里就不是 获取 bean 了,而是需要创建 bean
// 例如: ioc.getBean("person","xiaomao") ,这种情况会跳到下面的 else 分支中,就不是获取 bean,而是创建 bean
if (sharedInstance != null && args == null) {
if (logger.isDebugEnabled()) {
if (isSingletonCurrentlyInCreation(beanName)) {
logger.debug("Returning eagerly cached instance of singleton bean '" + beanName +
"' that is not fully initialized yet - a consequence of a circular reference");
}
else {
logger.debug("Returning cached instance of singleton bean '" + beanName + "'");
}
}
bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);
}
// 执行创建 bean 的操作
// 如果我们通过 getBean(beanName,args) 传入了 args 参数,那么我们就不是获取 bean 了,而是要创建 bean
else {
// 如果已经创建了该 beanName 的 prototype ,那么抛出异常
if (isPrototypeCurrentlyInCreation(beanName)) {
throw new BeanCurrentlyInCreationException(beanName);
}
// 检查是否这个 BeanDefinition 对象已经存在父容器中了
BeanFactory parentBeanFactory = getParentBeanFactory();
// 如果自身容器中不存在,父容器中存在该 BeanDefiniton
if (parentBeanFactory != null && !containsBeanDefinition(beanName)) {
// Not found -> check parent.
String nameToLookup = originalBeanName(name);
if (args != null) {
// Delegation to parent with explicit args.
return (T) parentBeanFactory.getBean(nameToLookup, args);
}
else {
// No args -> delegate to standard getBean method.
return parentBeanFactory.getBean(nameToLookup, requiredType);
}
}
// 标记已经创建了这个 bean
if (!typeCheckOnly) {
markBeanAsCreated(beanName);
}
try {
final RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
checkMergedBeanDefinition(mbd, beanName, args);
// Guarantee initialization of beans that the current bean depends on.
String[] dependsOn = mbd.getDependsOn();
if (dependsOn != null) {
for (String dep : dependsOn) {
if (isDependent(beanName, dep)) {
throw new BeanCreationException(mbd.getResourceDescription(), beanName,
"Circular depends-on relationship between '" + beanName + "' and '" + dep + "'");
}
registerDependentBean(dep, beanName);
getBean(dep);
}
}
// 创建 bean 实例对象
if (mbd.isSingleton()) {
sharedInstance = getSingleton(beanName, new ObjectFactory<Object>() {
@Override
public Object getObject() throws BeansException {
try {
// 创建 bean 对象,核心方法...(我们这里就不看了,还是蛮多的)
return createBean(beanName, mbd, args);
}
catch (BeansException ex) {
// Explicitly remove instance from singleton cache: It might have been put there
// eagerly by the creation process, to allow for circular reference resolution.
// Also remove any beans that received a temporary reference to the bean.
destroySingleton(beanName);
throw ex;
}
}
});
// 如果是普通 bean ,返回自身对象
// 如果是 FactoryBean 返回自身对象,而不是调用 getObject() 方法返回的对象
bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
}
else if (mbd.isPrototype()) {
// It's a prototype -> create a new instance.
Object prototypeInstance = null;
try {
beforePrototypeCreation(beanName);
prototypeInstance = createBean(beanName, mbd, args);
}
finally {
afterPrototypeCreation(beanName);
}
bean = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);
}
else {
String scopeName = mbd.getScope();
final Scope scope = this.scopes.get(scopeName);
if (scope == null) {
throw new IllegalStateException("No Scope registered for scope name '" + scopeName + "'");
}
try {
Object scopedInstance = scope.get(beanName, new ObjectFactory<Object>() {
@Override
public Object getObject() throws BeansException {
beforePrototypeCreation(beanName);
try {
return createBean(beanName, mbd, args);
}
finally {
afterPrototypeCreation(beanName);
}
}
});
bean = getObjectForBeanInstance(scopedInstance, name, beanName, mbd);
}
catch (IllegalStateException ex) {
throw new BeanCreationException(beanName,
"Scope '" + scopeName + "' is not active for the current thread; consider " +
"defining a scoped proxy for this bean if you intend to refer to it from a singleton",
ex);
}
}
}
catch (BeansException ex) {
cleanupAfterBeanCreationFailure(beanName);
throw ex;
}
}
// Check if required type matches the type of the actual bean instance.
if (requiredType != null && bean != null && !requiredType.isInstance(bean)) {
try {
return getTypeConverter().convertIfNecessary(bean, requiredType);
}
catch (TypeMismatchException ex) {
if (logger.isDebugEnabled()) {
logger.debug("Failed to convert bean '" + name + "' to required type '" +
ClassUtils.getQualifiedName(requiredType) + "'", ex);
}
throw new BeanNotOfRequiredTypeException(name, requiredType, bean.getClass());
}
}
return (T) bean;
}
看一下这个方法,虽然比较长,我们只关心我们需要的部分,上面这个方法不管最后执行哪一个分支,最终都会调用 bean = getObjectForBeanInstance(...) 这个方法,点进去看吧.
// AbstractBeanFactory 类中的方法,代码行号: 1607
protected Object getObjectForBeanInstance(
Object beanInstance, String name, String beanName, RootBeanDefinition mbd) {
// 两个判断条件
// BeanFactoryUtils.isFactoryDereference(name):判断 name 是否不为空,并且以 & 开头
// beanInstance instanceof FactoryBean:当前 bean 是否是 FactoryBean 的实现类
if (BeanFactoryUtils.isFactoryDereference(name) && !(beanInstance instanceof FactoryBean)) {
throw new BeanIsNotAFactoryException(transformedBeanName(name), beanInstance.getClass());
}
// 初始化的时候,如果是 FactoryBean ,那么上述两个判断条件都是成立的,直接返回一个 beanInstance 对象
// 获取对象的时候,如果通过 ioc.getBean("&person") 这种方式,那么也是直接返回一个 beanInstance 对象
// 这里的 beanInstance 是我们在 AbstractBeanFactory 类中通过调用 createBean(beanName, mbd, args)
// 方法创建的,它是一个 Person 类的对象,不是 FactoryBean 实现类调用 getObject() 方法生产的对象
if (!(beanInstance instanceof FactoryBean) || BeanFactoryUtils.isFactoryDereference(name)) {
return beanInstance;
}
// 如果是已经初始化完毕了,去 IOC 容器中获取 bean 实例对象的时候
// 如果通过 ioc.getBean("person") 获取 bean 实例对象,会执行如下代码
Object object = null;
if (mbd == null) {
object = getCachedObjectForFactoryBean(beanName);
}
if (object == null) {
// beanInstance 是 Person 对象,而 Person 又是实现了 FactoryBean 接口的
FactoryBean<?> factory = (FactoryBean<?>) beanInstance;
if (mbd == null && containsBeanDefinition(beanName)) {
mbd = getMergedLocalBeanDefinition(beanName);
}
boolean synthetic = (mbd != null && mbd.isSynthetic());
// 获取 FactoryBean 的核心方法....
object = getObjectFromFactoryBean(factory, beanName, !synthetic);
}
return object;
}
从上面代码我们知道, ioc.get("&person") 获取到的是 Person 类对象,如果我们要获取 Person 对象调用 getObject() 方法生产的 Mango 对象,该如何获取呢?
找到 getObjectFromFactoryBean(...) 方法,点进去看
protected Object getObjectFromFactoryBean(FactoryBean<?> factory, String beanName, boolean shouldPostProcess) {
if (factory.isSingleton() && containsSingleton(beanName)) {
synchronized (getSingletonMutex()) {
Object object = this.factoryBeanObjectCache.get(beanName);
if (object == null) {
// FactoryBean 调用 getObject() 方法生产的对象
object = doGetObjectFromFactoryBean(factory, beanName);
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 调用 getObject() 方法生产的对象
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;
}
}
细节就不看了,有一点是很明显的,不管判断条件如何,都会进入到 doGetObjectFromFactoryBean(factory, beanName) 这个方法里面,继续点进去看
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>() {
@Override
public Object run() throws Exception {
return factory.getObject();
}
}, acc);
}
catch (PrivilegedActionException pae) {
throw pae.getException();
}
}
else {
// 这里的 factory 就是 FactoryBean 实现类对象,我们这里就是 Person 类对象
// 根据继承的关系,子类中实现了 getObject() 方法,那么实际调用的就是子类里的 getObject()方法
// 也就是我们 Person 对象中的 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");
}
// 将BeanFactory 实现类对象通过调用 getObject() 方法生产的对象返回出去.
return object;
}